You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					756 lines
				
				26 KiB
			
		
		
			
		
	
	
					756 lines
				
				26 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								"""setuptools.command.egg_info
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Create a distribution's .egg-info directory and contents"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from distutils.filelist import FileList as _FileList
							 | 
						||
| 
								 | 
							
								from distutils.errors import DistutilsInternalError
							 | 
						||
| 
								 | 
							
								from distutils.util import convert_path
							 | 
						||
| 
								 | 
							
								from distutils import log
							 | 
						||
| 
								 | 
							
								import distutils.errors
							 | 
						||
| 
								 | 
							
								import distutils.filelist
							 | 
						||
| 
								 | 
							
								import functools
							 | 
						||
| 
								 | 
							
								import os
							 | 
						||
| 
								 | 
							
								import re
							 | 
						||
| 
								 | 
							
								import sys
							 | 
						||
| 
								 | 
							
								import io
							 | 
						||
| 
								 | 
							
								import warnings
							 | 
						||
| 
								 | 
							
								import time
							 | 
						||
| 
								 | 
							
								import collections
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from setuptools import Command
							 | 
						||
| 
								 | 
							
								from setuptools.command.sdist import sdist
							 | 
						||
| 
								 | 
							
								from setuptools.command.sdist import walk_revctrl
							 | 
						||
| 
								 | 
							
								from setuptools.command.setopt import edit_config
							 | 
						||
| 
								 | 
							
								from setuptools.command import bdist_egg
							 | 
						||
| 
								 | 
							
								from pkg_resources import (
							 | 
						||
| 
								 | 
							
								    parse_requirements, safe_name, parse_version,
							 | 
						||
| 
								 | 
							
								    safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
							 | 
						||
| 
								 | 
							
								import setuptools.unicode_utils as unicode_utils
							 | 
						||
| 
								 | 
							
								from setuptools.glob import glob
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from setuptools.extern import packaging
							 | 
						||
| 
								 | 
							
								from setuptools import SetuptoolsDeprecationWarning
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def translate_pattern(glob):  # noqa: C901  # is too complex (14)  # FIXME
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Translate a file path glob like '*.txt' in to a regular expression.
							 | 
						||
| 
								 | 
							
								    This differs from fnmatch.translate which allows wildcards to match
							 | 
						||
| 
								 | 
							
								    directory separators. It also knows about '**/' which matches any number of
							 | 
						||
| 
								 | 
							
								    directories.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    pat = ''
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # This will split on '/' within [character classes]. This is deliberate.
							 | 
						||
| 
								 | 
							
								    chunks = glob.split(os.path.sep)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    sep = re.escape(os.sep)
							 | 
						||
| 
								 | 
							
								    valid_char = '[^%s]' % (sep,)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for c, chunk in enumerate(chunks):
							 | 
						||
| 
								 | 
							
								        last_chunk = c == len(chunks) - 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Chunks that are a literal ** are globstars. They match anything.
							 | 
						||
| 
								 | 
							
								        if chunk == '**':
							 | 
						||
| 
								 | 
							
								            if last_chunk:
							 | 
						||
| 
								 | 
							
								                # Match anything if this is the last component
							 | 
						||
| 
								 | 
							
								                pat += '.*'
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                # Match '(name/)*'
							 | 
						||
| 
								 | 
							
								                pat += '(?:%s+%s)*' % (valid_char, sep)
							 | 
						||
| 
								 | 
							
								            continue  # Break here as the whole path component has been handled
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Find any special characters in the remainder
							 | 
						||
| 
								 | 
							
								        i = 0
							 | 
						||
| 
								 | 
							
								        chunk_len = len(chunk)
							 | 
						||
| 
								 | 
							
								        while i < chunk_len:
							 | 
						||
| 
								 | 
							
								            char = chunk[i]
							 | 
						||
| 
								 | 
							
								            if char == '*':
							 | 
						||
| 
								 | 
							
								                # Match any number of name characters
							 | 
						||
| 
								 | 
							
								                pat += valid_char + '*'
							 | 
						||
| 
								 | 
							
								            elif char == '?':
							 | 
						||
| 
								 | 
							
								                # Match a name character
							 | 
						||
| 
								 | 
							
								                pat += valid_char
							 | 
						||
| 
								 | 
							
								            elif char == '[':
							 | 
						||
| 
								 | 
							
								                # Character class
							 | 
						||
| 
								 | 
							
								                inner_i = i + 1
							 | 
						||
| 
								 | 
							
								                # Skip initial !/] chars
							 | 
						||
| 
								 | 
							
								                if inner_i < chunk_len and chunk[inner_i] == '!':
							 | 
						||
| 
								 | 
							
								                    inner_i = inner_i + 1
							 | 
						||
| 
								 | 
							
								                if inner_i < chunk_len and chunk[inner_i] == ']':
							 | 
						||
| 
								 | 
							
								                    inner_i = inner_i + 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                # Loop till the closing ] is found
							 | 
						||
| 
								 | 
							
								                while inner_i < chunk_len and chunk[inner_i] != ']':
							 | 
						||
| 
								 | 
							
								                    inner_i = inner_i + 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if inner_i >= chunk_len:
							 | 
						||
| 
								 | 
							
								                    # Got to the end of the string without finding a closing ]
							 | 
						||
| 
								 | 
							
								                    # Do not treat this as a matching group, but as a literal [
							 | 
						||
| 
								 | 
							
								                    pat += re.escape(char)
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    # Grab the insides of the [brackets]
							 | 
						||
| 
								 | 
							
								                    inner = chunk[i + 1:inner_i]
							 | 
						||
| 
								 | 
							
								                    char_class = ''
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    # Class negation
							 | 
						||
| 
								 | 
							
								                    if inner[0] == '!':
							 | 
						||
| 
								 | 
							
								                        char_class = '^'
							 | 
						||
| 
								 | 
							
								                        inner = inner[1:]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    char_class += re.escape(inner)
							 | 
						||
| 
								 | 
							
								                    pat += '[%s]' % (char_class,)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    # Skip to the end ]
							 | 
						||
| 
								 | 
							
								                    i = inner_i
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                pat += re.escape(char)
							 | 
						||
| 
								 | 
							
								            i += 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Join each chunk with the dir separator
							 | 
						||
| 
								 | 
							
								        if not last_chunk:
							 | 
						||
| 
								 | 
							
								            pat += sep
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    pat += r'\Z'
							 | 
						||
| 
								 | 
							
								    return re.compile(pat, flags=re.MULTILINE | re.DOTALL)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class InfoCommon:
							 | 
						||
| 
								 | 
							
								    tag_build = None
							 | 
						||
| 
								 | 
							
								    tag_date = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def name(self):
							 | 
						||
| 
								 | 
							
								        return safe_name(self.distribution.get_name())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def tagged_version(self):
							 | 
						||
| 
								 | 
							
								        return safe_version(self._maybe_tag(self.distribution.get_version()))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _maybe_tag(self, version):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        egg_info may be called more than once for a distribution,
							 | 
						||
| 
								 | 
							
								        in which case the version string already contains all tags.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return (
							 | 
						||
| 
								 | 
							
								            version if self.vtags and version.endswith(self.vtags)
							 | 
						||
| 
								 | 
							
								            else version + self.vtags
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def tags(self):
							 | 
						||
| 
								 | 
							
								        version = ''
							 | 
						||
| 
								 | 
							
								        if self.tag_build:
							 | 
						||
| 
								 | 
							
								            version += self.tag_build
							 | 
						||
| 
								 | 
							
								        if self.tag_date:
							 | 
						||
| 
								 | 
							
								            version += time.strftime("-%Y%m%d")
							 | 
						||
| 
								 | 
							
								        return version
							 | 
						||
| 
								 | 
							
								    vtags = property(tags)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class egg_info(InfoCommon, Command):
							 | 
						||
| 
								 | 
							
								    description = "create a distribution's .egg-info directory"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    user_options = [
							 | 
						||
| 
								 | 
							
								        ('egg-base=', 'e', "directory containing .egg-info directories"
							 | 
						||
| 
								 | 
							
								                           " (default: top of the source tree)"),
							 | 
						||
| 
								 | 
							
								        ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
							 | 
						||
| 
								 | 
							
								        ('tag-build=', 'b', "Specify explicit tag to add to version number"),
							 | 
						||
| 
								 | 
							
								        ('no-date', 'D', "Don't include date stamp [default]"),
							 | 
						||
| 
								 | 
							
								    ]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    boolean_options = ['tag-date']
							 | 
						||
| 
								 | 
							
								    negative_opt = {
							 | 
						||
| 
								 | 
							
								        'no-date': 'tag-date',
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def initialize_options(self):
							 | 
						||
| 
								 | 
							
								        self.egg_base = None
							 | 
						||
| 
								 | 
							
								        self.egg_name = None
							 | 
						||
| 
								 | 
							
								        self.egg_info = None
							 | 
						||
| 
								 | 
							
								        self.egg_version = None
							 | 
						||
| 
								 | 
							
								        self.broken_egg_info = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ####################################
							 | 
						||
| 
								 | 
							
								    # allow the 'tag_svn_revision' to be detected and
							 | 
						||
| 
								 | 
							
								    # set, supporting sdists built on older Setuptools.
							 | 
						||
| 
								 | 
							
								    @property
							 | 
						||
| 
								 | 
							
								    def tag_svn_revision(self):
							 | 
						||
| 
								 | 
							
								        pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @tag_svn_revision.setter
							 | 
						||
| 
								 | 
							
								    def tag_svn_revision(self, value):
							 | 
						||
| 
								 | 
							
								        pass
							 | 
						||
| 
								 | 
							
								    ####################################
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def save_version_info(self, filename):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Materialize the value of date into the
							 | 
						||
| 
								 | 
							
								        build tag. Install build keys in a deterministic order
							 | 
						||
| 
								 | 
							
								        to avoid arbitrary reordering on subsequent builds.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        egg_info = collections.OrderedDict()
							 | 
						||
| 
								 | 
							
								        # follow the order these keys would have been added
							 | 
						||
| 
								 | 
							
								        # when PYTHONHASHSEED=0
							 | 
						||
| 
								 | 
							
								        egg_info['tag_build'] = self.tags()
							 | 
						||
| 
								 | 
							
								        egg_info['tag_date'] = 0
							 | 
						||
| 
								 | 
							
								        edit_config(filename, dict(egg_info=egg_info))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def finalize_options(self):
							 | 
						||
| 
								 | 
							
								        # Note: we need to capture the current value returned
							 | 
						||
| 
								 | 
							
								        # by `self.tagged_version()`, so we can later update
							 | 
						||
| 
								 | 
							
								        # `self.distribution.metadata.version` without
							 | 
						||
| 
								 | 
							
								        # repercussions.
							 | 
						||
| 
								 | 
							
								        self.egg_name = self.name
							 | 
						||
| 
								 | 
							
								        self.egg_version = self.tagged_version()
							 | 
						||
| 
								 | 
							
								        parsed_version = parse_version(self.egg_version)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            is_version = isinstance(parsed_version, packaging.version.Version)
							 | 
						||
| 
								 | 
							
								            spec = (
							 | 
						||
| 
								 | 
							
								                "%s==%s" if is_version else "%s===%s"
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								            list(
							 | 
						||
| 
								 | 
							
								                parse_requirements(spec % (self.egg_name, self.egg_version))
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        except ValueError as e:
							 | 
						||
| 
								 | 
							
								            raise distutils.errors.DistutilsOptionError(
							 | 
						||
| 
								 | 
							
								                "Invalid distribution name or version syntax: %s-%s" %
							 | 
						||
| 
								 | 
							
								                (self.egg_name, self.egg_version)
							 | 
						||
| 
								 | 
							
								            ) from e
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if self.egg_base is None:
							 | 
						||
| 
								 | 
							
								            dirs = self.distribution.package_dir
							 | 
						||
| 
								 | 
							
								            self.egg_base = (dirs or {}).get('', os.curdir)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.ensure_dirname('egg_base')
							 | 
						||
| 
								 | 
							
								        self.egg_info = to_filename(self.egg_name) + '.egg-info'
							 | 
						||
| 
								 | 
							
								        if self.egg_base != os.curdir:
							 | 
						||
| 
								 | 
							
								            self.egg_info = os.path.join(self.egg_base, self.egg_info)
							 | 
						||
| 
								 | 
							
								        if '-' in self.egg_name:
							 | 
						||
| 
								 | 
							
								            self.check_broken_egg_info()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Set package version for the benefit of dumber commands
							 | 
						||
| 
								 | 
							
								        # (e.g. sdist, bdist_wininst, etc.)
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        self.distribution.metadata.version = self.egg_version
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # If we bootstrapped around the lack of a PKG-INFO, as might be the
							 | 
						||
| 
								 | 
							
								        # case in a fresh checkout, make sure that any special tags get added
							 | 
						||
| 
								 | 
							
								        # to the version info
							 | 
						||
| 
								 | 
							
								        #
							 | 
						||
| 
								 | 
							
								        pd = self.distribution._patched_dist
							 | 
						||
| 
								 | 
							
								        if pd is not None and pd.key == self.egg_name.lower():
							 | 
						||
| 
								 | 
							
								            pd._version = self.egg_version
							 | 
						||
| 
								 | 
							
								            pd._parsed_version = parse_version(self.egg_version)
							 | 
						||
| 
								 | 
							
								            self.distribution._patched_dist = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def write_or_delete_file(self, what, filename, data, force=False):
							 | 
						||
| 
								 | 
							
								        """Write `data` to `filename` or delete if empty
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        If `data` is non-empty, this routine is the same as ``write_file()``.
							 | 
						||
| 
								 | 
							
								        If `data` is empty but not ``None``, this is the same as calling
							 | 
						||
| 
								 | 
							
								        ``delete_file(filename)`.  If `data` is ``None``, then this is a no-op
							 | 
						||
| 
								 | 
							
								        unless `filename` exists, in which case a warning is issued about the
							 | 
						||
| 
								 | 
							
								        orphaned file (if `force` is false), or deleted (if `force` is true).
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if data:
							 | 
						||
| 
								 | 
							
								            self.write_file(what, filename, data)
							 | 
						||
| 
								 | 
							
								        elif os.path.exists(filename):
							 | 
						||
| 
								 | 
							
								            if data is None and not force:
							 | 
						||
| 
								 | 
							
								                log.warn(
							 | 
						||
| 
								 | 
							
								                    "%s not set in setup(), but %s exists", what, filename
							 | 
						||
| 
								 | 
							
								                )
							 | 
						||
| 
								 | 
							
								                return
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                self.delete_file(filename)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def write_file(self, what, filename, data):
							 | 
						||
| 
								 | 
							
								        """Write `data` to `filename` (if not a dry run) after announcing it
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        `what` is used in a log message to identify what is being written
							 | 
						||
| 
								 | 
							
								        to the file.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        log.info("writing %s to %s", what, filename)
							 | 
						||
| 
								 | 
							
								        data = data.encode("utf-8")
							 | 
						||
| 
								 | 
							
								        if not self.dry_run:
							 | 
						||
| 
								 | 
							
								            f = open(filename, 'wb')
							 | 
						||
| 
								 | 
							
								            f.write(data)
							 | 
						||
| 
								 | 
							
								            f.close()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def delete_file(self, filename):
							 | 
						||
| 
								 | 
							
								        """Delete `filename` (if not a dry run) after announcing it"""
							 | 
						||
| 
								 | 
							
								        log.info("deleting %s", filename)
							 | 
						||
| 
								 | 
							
								        if not self.dry_run:
							 | 
						||
| 
								 | 
							
								            os.unlink(filename)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def run(self):
							 | 
						||
| 
								 | 
							
								        self.mkpath(self.egg_info)
							 | 
						||
| 
								 | 
							
								        os.utime(self.egg_info, None)
							 | 
						||
| 
								 | 
							
								        installer = self.distribution.fetch_build_egg
							 | 
						||
| 
								 | 
							
								        for ep in iter_entry_points('egg_info.writers'):
							 | 
						||
| 
								 | 
							
								            ep.require(installer=installer)
							 | 
						||
| 
								 | 
							
								            writer = ep.resolve()
							 | 
						||
| 
								 | 
							
								            writer(self, ep.name, os.path.join(self.egg_info, ep.name))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Get rid of native_libs.txt if it was put there by older bdist_egg
							 | 
						||
| 
								 | 
							
								        nl = os.path.join(self.egg_info, "native_libs.txt")
							 | 
						||
| 
								 | 
							
								        if os.path.exists(nl):
							 | 
						||
| 
								 | 
							
								            self.delete_file(nl)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.find_sources()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def find_sources(self):
							 | 
						||
| 
								 | 
							
								        """Generate SOURCES.txt manifest file"""
							 | 
						||
| 
								 | 
							
								        manifest_filename = os.path.join(self.egg_info, "SOURCES.txt")
							 | 
						||
| 
								 | 
							
								        mm = manifest_maker(self.distribution)
							 | 
						||
| 
								 | 
							
								        mm.manifest = manifest_filename
							 | 
						||
| 
								 | 
							
								        mm.run()
							 | 
						||
| 
								 | 
							
								        self.filelist = mm.filelist
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_broken_egg_info(self):
							 | 
						||
| 
								 | 
							
								        bei = self.egg_name + '.egg-info'
							 | 
						||
| 
								 | 
							
								        if self.egg_base != os.curdir:
							 | 
						||
| 
								 | 
							
								            bei = os.path.join(self.egg_base, bei)
							 | 
						||
| 
								 | 
							
								        if os.path.exists(bei):
							 | 
						||
| 
								 | 
							
								            log.warn(
							 | 
						||
| 
								 | 
							
								                "-" * 78 + '\n'
							 | 
						||
| 
								 | 
							
								                "Note: Your current .egg-info directory has a '-' in its name;"
							 | 
						||
| 
								 | 
							
								                '\nthis will not work correctly with "setup.py develop".\n\n'
							 | 
						||
| 
								 | 
							
								                'Please rename %s to %s to correct this problem.\n' + '-' * 78,
							 | 
						||
| 
								 | 
							
								                bei, self.egg_info
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								            self.broken_egg_info = self.egg_info
							 | 
						||
| 
								 | 
							
								            self.egg_info = bei  # make it work for now
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class FileList(_FileList):
							 | 
						||
| 
								 | 
							
								    # Implementations of the various MANIFEST.in commands
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def process_template_line(self, line):
							 | 
						||
| 
								 | 
							
								        # Parse the line: split it up, make sure the right number of words
							 | 
						||
| 
								 | 
							
								        # is there, and return the relevant words.  'action' is always
							 | 
						||
| 
								 | 
							
								        # defined: it's the first word of the line.  Which of the other
							 | 
						||
| 
								 | 
							
								        # three are defined depends on the action; it'll be either
							 | 
						||
| 
								 | 
							
								        # patterns, (dir and patterns), or (dir_pattern).
							 | 
						||
| 
								 | 
							
								        (action, patterns, dir, dir_pattern) = self._parse_template_line(line)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        action_map = {
							 | 
						||
| 
								 | 
							
								            'include': self.include,
							 | 
						||
| 
								 | 
							
								            'exclude': self.exclude,
							 | 
						||
| 
								 | 
							
								            'global-include': self.global_include,
							 | 
						||
| 
								 | 
							
								            'global-exclude': self.global_exclude,
							 | 
						||
| 
								 | 
							
								            'recursive-include': functools.partial(
							 | 
						||
| 
								 | 
							
								                self.recursive_include, dir,
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								            'recursive-exclude': functools.partial(
							 | 
						||
| 
								 | 
							
								                self.recursive_exclude, dir,
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								            'graft': self.graft,
							 | 
						||
| 
								 | 
							
								            'prune': self.prune,
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        log_map = {
							 | 
						||
| 
								 | 
							
								            'include': "warning: no files found matching '%s'",
							 | 
						||
| 
								 | 
							
								            'exclude': (
							 | 
						||
| 
								 | 
							
								                "warning: no previously-included files found "
							 | 
						||
| 
								 | 
							
								                "matching '%s'"
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								            'global-include': (
							 | 
						||
| 
								 | 
							
								                "warning: no files found matching '%s' "
							 | 
						||
| 
								 | 
							
								                "anywhere in distribution"
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								            'global-exclude': (
							 | 
						||
| 
								 | 
							
								                "warning: no previously-included files matching "
							 | 
						||
| 
								 | 
							
								                "'%s' found anywhere in distribution"
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								            'recursive-include': (
							 | 
						||
| 
								 | 
							
								                "warning: no files found matching '%s' "
							 | 
						||
| 
								 | 
							
								                "under directory '%s'"
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								            'recursive-exclude': (
							 | 
						||
| 
								 | 
							
								                "warning: no previously-included files matching "
							 | 
						||
| 
								 | 
							
								                "'%s' found under directory '%s'"
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								            'graft': "warning: no directories found matching '%s'",
							 | 
						||
| 
								 | 
							
								            'prune': "no previously-included directories found matching '%s'",
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            process_action = action_map[action]
							 | 
						||
| 
								 | 
							
								        except KeyError:
							 | 
						||
| 
								 | 
							
								            raise DistutilsInternalError(
							 | 
						||
| 
								 | 
							
								                "this cannot happen: invalid action '{action!s}'".
							 | 
						||
| 
								 | 
							
								                format(action=action),
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # OK, now we know that the action is valid and we have the
							 | 
						||
| 
								 | 
							
								        # right number of words on the line for that action -- so we
							 | 
						||
| 
								 | 
							
								        # can proceed with minimal error-checking.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        action_is_recursive = action.startswith('recursive-')
							 | 
						||
| 
								 | 
							
								        if action in {'graft', 'prune'}:
							 | 
						||
| 
								 | 
							
								            patterns = [dir_pattern]
							 | 
						||
| 
								 | 
							
								        extra_log_args = (dir, ) if action_is_recursive else ()
							 | 
						||
| 
								 | 
							
								        log_tmpl = log_map[action]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.debug_print(
							 | 
						||
| 
								 | 
							
								            ' '.join(
							 | 
						||
| 
								 | 
							
								                [action] +
							 | 
						||
| 
								 | 
							
								                ([dir] if action_is_recursive else []) +
							 | 
						||
| 
								 | 
							
								                patterns,
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								        for pattern in patterns:
							 | 
						||
| 
								 | 
							
								            if not process_action(pattern):
							 | 
						||
| 
								 | 
							
								                log.warn(log_tmpl, pattern, *extra_log_args)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _remove_files(self, predicate):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Remove all files from the file list that match the predicate.
							 | 
						||
| 
								 | 
							
								        Return True if any matching files were removed
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        found = False
							 | 
						||
| 
								 | 
							
								        for i in range(len(self.files) - 1, -1, -1):
							 | 
						||
| 
								 | 
							
								            if predicate(self.files[i]):
							 | 
						||
| 
								 | 
							
								                self.debug_print(" removing " + self.files[i])
							 | 
						||
| 
								 | 
							
								                del self.files[i]
							 | 
						||
| 
								 | 
							
								                found = True
							 | 
						||
| 
								 | 
							
								        return found
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def include(self, pattern):
							 | 
						||
| 
								 | 
							
								        """Include files that match 'pattern'."""
							 | 
						||
| 
								 | 
							
								        found = [f for f in glob(pattern) if not os.path.isdir(f)]
							 | 
						||
| 
								 | 
							
								        self.extend(found)
							 | 
						||
| 
								 | 
							
								        return bool(found)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def exclude(self, pattern):
							 | 
						||
| 
								 | 
							
								        """Exclude files that match 'pattern'."""
							 | 
						||
| 
								 | 
							
								        match = translate_pattern(pattern)
							 | 
						||
| 
								 | 
							
								        return self._remove_files(match.match)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def recursive_include(self, dir, pattern):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Include all files anywhere in 'dir/' that match the pattern.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        full_pattern = os.path.join(dir, '**', pattern)
							 | 
						||
| 
								 | 
							
								        found = [f for f in glob(full_pattern, recursive=True)
							 | 
						||
| 
								 | 
							
								                 if not os.path.isdir(f)]
							 | 
						||
| 
								 | 
							
								        self.extend(found)
							 | 
						||
| 
								 | 
							
								        return bool(found)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def recursive_exclude(self, dir, pattern):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Exclude any file anywhere in 'dir/' that match the pattern.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        match = translate_pattern(os.path.join(dir, '**', pattern))
							 | 
						||
| 
								 | 
							
								        return self._remove_files(match.match)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def graft(self, dir):
							 | 
						||
| 
								 | 
							
								        """Include all files from 'dir/'."""
							 | 
						||
| 
								 | 
							
								        found = [
							 | 
						||
| 
								 | 
							
								            item
							 | 
						||
| 
								 | 
							
								            for match_dir in glob(dir)
							 | 
						||
| 
								 | 
							
								            for item in distutils.filelist.findall(match_dir)
							 | 
						||
| 
								 | 
							
								        ]
							 | 
						||
| 
								 | 
							
								        self.extend(found)
							 | 
						||
| 
								 | 
							
								        return bool(found)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def prune(self, dir):
							 | 
						||
| 
								 | 
							
								        """Filter out files from 'dir/'."""
							 | 
						||
| 
								 | 
							
								        match = translate_pattern(os.path.join(dir, '**'))
							 | 
						||
| 
								 | 
							
								        return self._remove_files(match.match)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def global_include(self, pattern):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Include all files anywhere in the current directory that match the
							 | 
						||
| 
								 | 
							
								        pattern. This is very inefficient on large file trees.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if self.allfiles is None:
							 | 
						||
| 
								 | 
							
								            self.findall()
							 | 
						||
| 
								 | 
							
								        match = translate_pattern(os.path.join('**', pattern))
							 | 
						||
| 
								 | 
							
								        found = [f for f in self.allfiles if match.match(f)]
							 | 
						||
| 
								 | 
							
								        self.extend(found)
							 | 
						||
| 
								 | 
							
								        return bool(found)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def global_exclude(self, pattern):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Exclude all files anywhere that match the pattern.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        match = translate_pattern(os.path.join('**', pattern))
							 | 
						||
| 
								 | 
							
								        return self._remove_files(match.match)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def append(self, item):
							 | 
						||
| 
								 | 
							
								        if item.endswith('\r'):  # Fix older sdists built on Windows
							 | 
						||
| 
								 | 
							
								            item = item[:-1]
							 | 
						||
| 
								 | 
							
								        path = convert_path(item)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if self._safe_path(path):
							 | 
						||
| 
								 | 
							
								            self.files.append(path)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def extend(self, paths):
							 | 
						||
| 
								 | 
							
								        self.files.extend(filter(self._safe_path, paths))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _repair(self):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Replace self.files with only safe paths
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Because some owners of FileList manipulate the underlying
							 | 
						||
| 
								 | 
							
								        ``files`` attribute directly, this method must be called to
							 | 
						||
| 
								 | 
							
								        repair those paths.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        self.files = list(filter(self._safe_path, self.files))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _safe_path(self, path):
							 | 
						||
| 
								 | 
							
								        enc_warn = "'%s' not %s encodable -- skipping"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # To avoid accidental trans-codings errors, first to unicode
							 | 
						||
| 
								 | 
							
								        u_path = unicode_utils.filesys_decode(path)
							 | 
						||
| 
								 | 
							
								        if u_path is None:
							 | 
						||
| 
								 | 
							
								            log.warn("'%s' in unexpected encoding -- skipping" % path)
							 | 
						||
| 
								 | 
							
								            return False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Must ensure utf-8 encodability
							 | 
						||
| 
								 | 
							
								        utf8_path = unicode_utils.try_encode(u_path, "utf-8")
							 | 
						||
| 
								 | 
							
								        if utf8_path is None:
							 | 
						||
| 
								 | 
							
								            log.warn(enc_warn, path, 'utf-8')
							 | 
						||
| 
								 | 
							
								            return False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            # accept is either way checks out
							 | 
						||
| 
								 | 
							
								            if os.path.exists(u_path) or os.path.exists(utf8_path):
							 | 
						||
| 
								 | 
							
								                return True
							 | 
						||
| 
								 | 
							
								        # this will catch any encode errors decoding u_path
							 | 
						||
| 
								 | 
							
								        except UnicodeEncodeError:
							 | 
						||
| 
								 | 
							
								            log.warn(enc_warn, path, sys.getfilesystemencoding())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class manifest_maker(sdist):
							 | 
						||
| 
								 | 
							
								    template = "MANIFEST.in"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def initialize_options(self):
							 | 
						||
| 
								 | 
							
								        self.use_defaults = 1
							 | 
						||
| 
								 | 
							
								        self.prune = 1
							 | 
						||
| 
								 | 
							
								        self.manifest_only = 1
							 | 
						||
| 
								 | 
							
								        self.force_manifest = 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def finalize_options(self):
							 | 
						||
| 
								 | 
							
								        pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def run(self):
							 | 
						||
| 
								 | 
							
								        self.filelist = FileList()
							 | 
						||
| 
								 | 
							
								        if not os.path.exists(self.manifest):
							 | 
						||
| 
								 | 
							
								            self.write_manifest()  # it must exist so it'll get in the list
							 | 
						||
| 
								 | 
							
								        self.add_defaults()
							 | 
						||
| 
								 | 
							
								        if os.path.exists(self.template):
							 | 
						||
| 
								 | 
							
								            self.read_template()
							 | 
						||
| 
								 | 
							
								        self.add_license_files()
							 | 
						||
| 
								 | 
							
								        self.prune_file_list()
							 | 
						||
| 
								 | 
							
								        self.filelist.sort()
							 | 
						||
| 
								 | 
							
								        self.filelist.remove_duplicates()
							 | 
						||
| 
								 | 
							
								        self.write_manifest()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _manifest_normalize(self, path):
							 | 
						||
| 
								 | 
							
								        path = unicode_utils.filesys_decode(path)
							 | 
						||
| 
								 | 
							
								        return path.replace(os.sep, '/')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def write_manifest(self):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Write the file list in 'self.filelist' to the manifest file
							 | 
						||
| 
								 | 
							
								        named by 'self.manifest'.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        self.filelist._repair()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Now _repairs should encodability, but not unicode
							 | 
						||
| 
								 | 
							
								        files = [self._manifest_normalize(f) for f in self.filelist.files]
							 | 
						||
| 
								 | 
							
								        msg = "writing manifest file '%s'" % self.manifest
							 | 
						||
| 
								 | 
							
								        self.execute(write_file, (self.manifest, files), msg)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def warn(self, msg):
							 | 
						||
| 
								 | 
							
								        if not self._should_suppress_warning(msg):
							 | 
						||
| 
								 | 
							
								            sdist.warn(self, msg)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @staticmethod
							 | 
						||
| 
								 | 
							
								    def _should_suppress_warning(msg):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        suppress missing-file warnings from sdist
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return re.match(r"standard file .*not found", msg)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def add_defaults(self):
							 | 
						||
| 
								 | 
							
								        sdist.add_defaults(self)
							 | 
						||
| 
								 | 
							
								        self.filelist.append(self.template)
							 | 
						||
| 
								 | 
							
								        self.filelist.append(self.manifest)
							 | 
						||
| 
								 | 
							
								        rcfiles = list(walk_revctrl())
							 | 
						||
| 
								 | 
							
								        if rcfiles:
							 | 
						||
| 
								 | 
							
								            self.filelist.extend(rcfiles)
							 | 
						||
| 
								 | 
							
								        elif os.path.exists(self.manifest):
							 | 
						||
| 
								 | 
							
								            self.read_manifest()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if os.path.exists("setup.py"):
							 | 
						||
| 
								 | 
							
								            # setup.py should be included by default, even if it's not
							 | 
						||
| 
								 | 
							
								            # the script called to create the sdist
							 | 
						||
| 
								 | 
							
								            self.filelist.append("setup.py")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ei_cmd = self.get_finalized_command('egg_info')
							 | 
						||
| 
								 | 
							
								        self.filelist.graft(ei_cmd.egg_info)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def add_license_files(self):
							 | 
						||
| 
								 | 
							
								        license_files = self.distribution.metadata.license_files or []
							 | 
						||
| 
								 | 
							
								        for lf in license_files:
							 | 
						||
| 
								 | 
							
								            log.info("adding license file '%s'", lf)
							 | 
						||
| 
								 | 
							
								            pass
							 | 
						||
| 
								 | 
							
								        self.filelist.extend(license_files)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def prune_file_list(self):
							 | 
						||
| 
								 | 
							
								        build = self.get_finalized_command('build')
							 | 
						||
| 
								 | 
							
								        base_dir = self.distribution.get_fullname()
							 | 
						||
| 
								 | 
							
								        self.filelist.prune(build.build_base)
							 | 
						||
| 
								 | 
							
								        self.filelist.prune(base_dir)
							 | 
						||
| 
								 | 
							
								        sep = re.escape(os.sep)
							 | 
						||
| 
								 | 
							
								        self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep,
							 | 
						||
| 
								 | 
							
								                                      is_regex=1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _safe_data_files(self, build_py):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        The parent class implementation of this method
							 | 
						||
| 
								 | 
							
								        (``sdist``) will try to include data files, which
							 | 
						||
| 
								 | 
							
								        might cause recursion problems when
							 | 
						||
| 
								 | 
							
								        ``include_package_data=True``.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        Therefore, avoid triggering any attempt of
							 | 
						||
| 
								 | 
							
								        analyzing/building the manifest again.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if hasattr(build_py, 'get_data_files_without_manifest'):
							 | 
						||
| 
								 | 
							
								            return build_py.get_data_files_without_manifest()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        warnings.warn(
							 | 
						||
| 
								 | 
							
								            "Custom 'build_py' does not implement "
							 | 
						||
| 
								 | 
							
								            "'get_data_files_without_manifest'.\nPlease extend command classes"
							 | 
						||
| 
								 | 
							
								            " from setuptools instead of distutils.",
							 | 
						||
| 
								 | 
							
								            SetuptoolsDeprecationWarning
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								        return build_py.get_data_files()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def write_file(filename, contents):
							 | 
						||
| 
								 | 
							
								    """Create a file with the specified name and write 'contents' (a
							 | 
						||
| 
								 | 
							
								    sequence of strings without line terminators) to it.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    contents = "\n".join(contents)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # assuming the contents has been vetted for utf-8 encoding
							 | 
						||
| 
								 | 
							
								    contents = contents.encode("utf-8")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    with open(filename, "wb") as f:  # always write POSIX-style manifest
							 | 
						||
| 
								 | 
							
								        f.write(contents)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def write_pkg_info(cmd, basename, filename):
							 | 
						||
| 
								 | 
							
								    log.info("writing %s", filename)
							 | 
						||
| 
								 | 
							
								    if not cmd.dry_run:
							 | 
						||
| 
								 | 
							
								        metadata = cmd.distribution.metadata
							 | 
						||
| 
								 | 
							
								        metadata.version, oldver = cmd.egg_version, metadata.version
							 | 
						||
| 
								 | 
							
								        metadata.name, oldname = cmd.egg_name, metadata.name
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            # write unescaped data to PKG-INFO, so older pkg_resources
							 | 
						||
| 
								 | 
							
								            # can still parse it
							 | 
						||
| 
								 | 
							
								            metadata.write_pkg_info(cmd.egg_info)
							 | 
						||
| 
								 | 
							
								        finally:
							 | 
						||
| 
								 | 
							
								            metadata.name, metadata.version = oldname, oldver
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        safe = getattr(cmd.distribution, 'zip_safe', None)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        bdist_egg.write_safety_flag(cmd.egg_info, safe)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def warn_depends_obsolete(cmd, basename, filename):
							 | 
						||
| 
								 | 
							
								    if os.path.exists(filename):
							 | 
						||
| 
								 | 
							
								        log.warn(
							 | 
						||
| 
								 | 
							
								            "WARNING: 'depends.txt' is not used by setuptools 0.6!\n"
							 | 
						||
| 
								 | 
							
								            "Use the install_requires/extras_require setup() args instead."
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _write_requirements(stream, reqs):
							 | 
						||
| 
								 | 
							
								    lines = yield_lines(reqs or ())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def append_cr(line):
							 | 
						||
| 
								 | 
							
								        return line + '\n'
							 | 
						||
| 
								 | 
							
								    lines = map(append_cr, sorted(lines))
							 | 
						||
| 
								 | 
							
								    stream.writelines(lines)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def write_requirements(cmd, basename, filename):
							 | 
						||
| 
								 | 
							
								    dist = cmd.distribution
							 | 
						||
| 
								 | 
							
								    data = io.StringIO()
							 | 
						||
| 
								 | 
							
								    _write_requirements(data, dist.install_requires)
							 | 
						||
| 
								 | 
							
								    extras_require = dist.extras_require or {}
							 | 
						||
| 
								 | 
							
								    for extra in sorted(extras_require):
							 | 
						||
| 
								 | 
							
								        data.write('\n[{extra}]\n'.format(**vars()))
							 | 
						||
| 
								 | 
							
								        _write_requirements(data, extras_require[extra])
							 | 
						||
| 
								 | 
							
								    cmd.write_or_delete_file("requirements", filename, data.getvalue())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def write_setup_requirements(cmd, basename, filename):
							 | 
						||
| 
								 | 
							
								    data = io.StringIO()
							 | 
						||
| 
								 | 
							
								    _write_requirements(data, cmd.distribution.setup_requires)
							 | 
						||
| 
								 | 
							
								    cmd.write_or_delete_file("setup-requirements", filename, data.getvalue())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def write_toplevel_names(cmd, basename, filename):
							 | 
						||
| 
								 | 
							
								    pkgs = dict.fromkeys(
							 | 
						||
| 
								 | 
							
								        [
							 | 
						||
| 
								 | 
							
								            k.split('.', 1)[0]
							 | 
						||
| 
								 | 
							
								            for k in cmd.distribution.iter_distribution_names()
							 | 
						||
| 
								 | 
							
								        ]
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								    cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def overwrite_arg(cmd, basename, filename):
							 | 
						||
| 
								 | 
							
								    write_arg(cmd, basename, filename, True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def write_arg(cmd, basename, filename, force=False):
							 | 
						||
| 
								 | 
							
								    argname = os.path.splitext(basename)[0]
							 | 
						||
| 
								 | 
							
								    value = getattr(cmd.distribution, argname, None)
							 | 
						||
| 
								 | 
							
								    if value is not None:
							 | 
						||
| 
								 | 
							
								        value = '\n'.join(value) + '\n'
							 | 
						||
| 
								 | 
							
								    cmd.write_or_delete_file(argname, filename, value, force)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def write_entries(cmd, basename, filename):
							 | 
						||
| 
								 | 
							
								    ep = cmd.distribution.entry_points
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if isinstance(ep, str) or ep is None:
							 | 
						||
| 
								 | 
							
								        data = ep
							 | 
						||
| 
								 | 
							
								    elif ep is not None:
							 | 
						||
| 
								 | 
							
								        data = []
							 | 
						||
| 
								 | 
							
								        for section, contents in sorted(ep.items()):
							 | 
						||
| 
								 | 
							
								            if not isinstance(contents, str):
							 | 
						||
| 
								 | 
							
								                contents = EntryPoint.parse_group(section, contents)
							 | 
						||
| 
								 | 
							
								                contents = '\n'.join(sorted(map(str, contents.values())))
							 | 
						||
| 
								 | 
							
								            data.append('[%s]\n%s\n\n' % (section, contents))
							 | 
						||
| 
								 | 
							
								        data = ''.join(data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    cmd.write_or_delete_file('entry points', filename, data, True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def get_pkg_info_revision():
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Get a -r### off of PKG-INFO Version in case this is an sdist of
							 | 
						||
| 
								 | 
							
								    a subversion revision.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    warnings.warn(
							 | 
						||
| 
								 | 
							
								        "get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning)
							 | 
						||
| 
								 | 
							
								    if os.path.exists('PKG-INFO'):
							 | 
						||
| 
								 | 
							
								        with io.open('PKG-INFO') as f:
							 | 
						||
| 
								 | 
							
								            for line in f:
							 | 
						||
| 
								 | 
							
								                match = re.match(r"Version:.*-r(\d+)\s*$", line)
							 | 
						||
| 
								 | 
							
								                if match:
							 | 
						||
| 
								 | 
							
								                    return int(match.group(1))
							 | 
						||
| 
								 | 
							
								    return 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class EggInfoDeprecationWarning(SetuptoolsDeprecationWarning):
							 | 
						||
| 
								 | 
							
								    """Deprecated behavior warning for EggInfo, bypassing suppression."""
							 |