| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 | from distutils import logimport distutils.command.sdist as origimport osimport sysimport ioimport contextlibfrom setuptools.extern import six, ordered_setfrom .py36compat import sdist_add_defaultsimport pkg_resources_default_revctrl = listdef walk_revctrl(dirname=''):    """Find all files under revision control"""    for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):        for item in ep.load()(dirname):            yield itemclass sdist(sdist_add_defaults, orig.sdist):    """Smart sdist that finds anything supported by revision control"""    user_options = [        ('formats=', None,         "formats for source distribution (comma-separated list)"),        ('keep-temp', 'k',         "keep the distribution tree around after creating " +         "archive file(s)"),        ('dist-dir=', 'd',         "directory to put the source distribution archive(s) in "         "[default: dist]"),    ]    negative_opt = {}    README_EXTENSIONS = ['', '.rst', '.txt', '.md']    READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)    def run(self):        self.run_command('egg_info')        ei_cmd = self.get_finalized_command('egg_info')        self.filelist = ei_cmd.filelist        self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))        self.check_readme()        # Run sub commands        for cmd_name in self.get_sub_commands():            self.run_command(cmd_name)        self.make_distribution()        dist_files = getattr(self.distribution, 'dist_files', [])        for file in self.archive_files:            data = ('sdist', '', file)            if data not in dist_files:                dist_files.append(data)    def initialize_options(self):        orig.sdist.initialize_options(self)        self._default_to_gztar()    def _default_to_gztar(self):        # only needed on Python prior to 3.6.        if sys.version_info >= (3, 6, 0, 'beta', 1):            return        self.formats = ['gztar']    def make_distribution(self):        """        Workaround for #516        """        with self._remove_os_link():            orig.sdist.make_distribution(self)    @staticmethod    @contextlib.contextmanager    def _remove_os_link():        """        In a context, remove and restore os.link if it exists        """        class NoValue:            pass        orig_val = getattr(os, 'link', NoValue)        try:            del os.link        except Exception:            pass        try:            yield        finally:            if orig_val is not NoValue:                setattr(os, 'link', orig_val)    def __read_template_hack(self):        # This grody hack closes the template file (MANIFEST.in) if an        #  exception occurs during read_template.        # Doing so prevents an error when easy_install attempts to delete the        #  file.        try:            orig.sdist.read_template(self)        except Exception:            _, _, tb = sys.exc_info()            tb.tb_next.tb_frame.f_locals['template'].close()            raise    # Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle    #  has been fixed, so only override the method if we're using an earlier    #  Python.    has_leaky_handle = (        sys.version_info < (2, 7, 2)        or (3, 0) <= sys.version_info < (3, 1, 4)        or (3, 2) <= sys.version_info < (3, 2, 1)    )    if has_leaky_handle:        read_template = __read_template_hack    def _add_defaults_optional(self):        if six.PY2:            sdist_add_defaults._add_defaults_optional(self)        else:            super()._add_defaults_optional()        if os.path.isfile('pyproject.toml'):            self.filelist.append('pyproject.toml')    def _add_defaults_python(self):        """getting python files"""        if self.distribution.has_pure_modules():            build_py = self.get_finalized_command('build_py')            self.filelist.extend(build_py.get_source_files())            self._add_data_files(self._safe_data_files(build_py))    def _safe_data_files(self, build_py):        """        Extracting data_files from build_py is known to cause        infinite recursion errors when `include_package_data`        is enabled, so suppress it in that case.        """        if self.distribution.include_package_data:            return ()        return build_py.data_files    def _add_data_files(self, data_files):        """        Add data files as found in build_py.data_files.        """        self.filelist.extend(            os.path.join(src_dir, name)            for _, src_dir, _, filenames in data_files            for name in filenames        )    def _add_defaults_data_files(self):        try:            if six.PY2:                sdist_add_defaults._add_defaults_data_files(self)            else:                super()._add_defaults_data_files()        except TypeError:            log.warn("data_files contains unexpected objects")    def check_readme(self):        for f in self.READMES:            if os.path.exists(f):                return        else:            self.warn(                "standard file not found: should have one of " +                ', '.join(self.READMES)            )    def make_release_tree(self, base_dir, files):        orig.sdist.make_release_tree(self, base_dir, files)        # Save any egg_info command line options used to create this sdist        dest = os.path.join(base_dir, 'setup.cfg')        if hasattr(os, 'link') and os.path.exists(dest):            # unlink and re-copy, since it might be hard-linked, and            # we don't want to change the source version            os.unlink(dest)            self.copy_file('setup.cfg', dest)        self.get_finalized_command('egg_info').save_version_info(dest)    def _manifest_is_not_generated(self):        # check for special comment used in 2.7.1 and higher        if not os.path.isfile(self.manifest):            return False        with io.open(self.manifest, 'rb') as fp:            first_line = fp.readline()        return (first_line !=                '# file GENERATED by distutils, do NOT edit\n'.encode())    def read_manifest(self):        """Read the manifest file (named by 'self.manifest') and use it to        fill in 'self.filelist', the list of files to include in the source        distribution.        """        log.info("reading manifest file '%s'", self.manifest)        manifest = open(self.manifest, 'rb')        for line in manifest:            # The manifest must contain UTF-8. See #303.            if not six.PY2:                try:                    line = line.decode('UTF-8')                except UnicodeDecodeError:                    log.warn("%r not UTF-8 decodable -- skipping" % line)                    continue            # ignore comments and blank lines            line = line.strip()            if line.startswith('#') or not line:                continue            self.filelist.append(line)        manifest.close()    def check_license(self):        """Checks if license_file' or 'license_files' is configured and adds any        valid paths to 'self.filelist'.        """        files = ordered_set.OrderedSet()        opts = self.distribution.get_option_dict('metadata')        # ignore the source of the value        _, license_file = opts.get('license_file', (None, None))        if license_file is None:            log.debug("'license_file' option was not specified")        else:            files.add(license_file)        try:            files.update(self.distribution.metadata.license_files)        except TypeError:            log.warn("warning: 'license_files' option is malformed")        for f in files:            if not os.path.exists(f):                log.warn(                    "warning: Failed to find the configured license file '%s'",                    f)                files.remove(f)        self.filelist.extend(files)
 |