1import os
2from glob import glob
3from distutils.util import convert_path
4from distutils.command import sdist
5
6
7class sdist_add_defaults:
8    """
9    Mix-in providing forward-compatibility for functionality as found in
10    distutils on Python 3.7.
11
12    Do not edit the code in this class except to update functionality
13    as implemented in distutils. Instead, override in the subclass.
14    """
15
16    def add_defaults(self):
17        """Add all the default files to self.filelist:
18          - README or README.txt
19          - setup.py
20          - test/test*.py
21          - all pure Python modules mentioned in setup script
22          - all files pointed by package_data (build_py)
23          - all files defined in data_files.
24          - all files defined as scripts.
25          - all C sources listed as part of extensions or C libraries
26            in the setup script (doesn't catch C headers!)
27        Warns if (README or README.txt) or setup.py are missing; everything
28        else is optional.
29        """
30        self._add_defaults_standards()
31        self._add_defaults_optional()
32        self._add_defaults_python()
33        self._add_defaults_data_files()
34        self._add_defaults_ext()
35        self._add_defaults_c_libs()
36        self._add_defaults_scripts()
37
38    @staticmethod
39    def _cs_path_exists(fspath):
40        """
41        Case-sensitive path existence check
42
43        >>> sdist_add_defaults._cs_path_exists(__file__)
44        True
45        >>> sdist_add_defaults._cs_path_exists(__file__.upper())
46        False
47        """
48        if not os.path.exists(fspath):
49            return False
50        # make absolute so we always have a directory
51        abspath = os.path.abspath(fspath)
52        directory, filename = os.path.split(abspath)
53        return filename in os.listdir(directory)
54
55    def _add_defaults_standards(self):
56        standards = [self.READMES, self.distribution.script_name]
57        for fn in standards:
58            if isinstance(fn, tuple):
59                alts = fn
60                got_it = False
61                for fn in alts:
62                    if self._cs_path_exists(fn):
63                        got_it = True
64                        self.filelist.append(fn)
65                        break
66
67                if not got_it:
68                    self.warn("standard file not found: should have one of " +
69                              ', '.join(alts))
70            else:
71                if self._cs_path_exists(fn):
72                    self.filelist.append(fn)
73                else:
74                    self.warn("standard file '%s' not found" % fn)
75
76    def _add_defaults_optional(self):
77        optional = ['test/test*.py', 'setup.cfg']
78        for pattern in optional:
79            files = filter(os.path.isfile, glob(pattern))
80            self.filelist.extend(files)
81
82    def _add_defaults_python(self):
83        # build_py is used to get:
84        #  - python modules
85        #  - files defined in package_data
86        build_py = self.get_finalized_command('build_py')
87
88        # getting python files
89        if self.distribution.has_pure_modules():
90            self.filelist.extend(build_py.get_source_files())
91
92        # getting package_data files
93        # (computed in build_py.data_files by build_py.finalize_options)
94        for pkg, src_dir, build_dir, filenames in build_py.data_files:
95            for filename in filenames:
96                self.filelist.append(os.path.join(src_dir, filename))
97
98    def _add_defaults_data_files(self):
99        # getting distribution.data_files
100        if self.distribution.has_data_files():
101            for item in self.distribution.data_files:
102                if isinstance(item, str):
103                    # plain file
104                    item = convert_path(item)
105                    if os.path.isfile(item):
106                        self.filelist.append(item)
107                else:
108                    # a (dirname, filenames) tuple
109                    dirname, filenames = item
110                    for f in filenames:
111                        f = convert_path(f)
112                        if os.path.isfile(f):
113                            self.filelist.append(f)
114
115    def _add_defaults_ext(self):
116        if self.distribution.has_ext_modules():
117            build_ext = self.get_finalized_command('build_ext')
118            self.filelist.extend(build_ext.get_source_files())
119
120    def _add_defaults_c_libs(self):
121        if self.distribution.has_c_libraries():
122            build_clib = self.get_finalized_command('build_clib')
123            self.filelist.extend(build_clib.get_source_files())
124
125    def _add_defaults_scripts(self):
126        if self.distribution.has_scripts():
127            build_scripts = self.get_finalized_command('build_scripts')
128            self.filelist.extend(build_scripts.get_source_files())
129
130
131if hasattr(sdist.sdist, '_add_defaults_standards'):
132    # disable the functionality already available upstream
133    class sdist_add_defaults:  # noqa
134        pass
135