OLD | NEW |
(Empty) | |
| 1 from glob import glob |
| 2 from distutils.util import convert_path |
| 3 from distutils import log |
| 4 import distutils.command.sdist as orig |
| 5 import os |
| 6 import re |
| 7 import sys |
| 8 |
| 9 from setuptools import svn_utils |
| 10 from setuptools.compat import PY3 |
| 11 from setuptools.utils import cs_path_exists |
| 12 |
| 13 import pkg_resources |
| 14 |
| 15 READMES = ('README', 'README.rst', 'README.txt') |
| 16 |
| 17 |
| 18 def walk_revctrl(dirname=''): |
| 19 """Find all files under revision control""" |
| 20 for ep in pkg_resources.iter_entry_points('setuptools.file_finders'): |
| 21 for item in ep.load()(dirname): |
| 22 yield item |
| 23 |
| 24 |
| 25 # TODO will need test case |
| 26 class re_finder(object): |
| 27 """ |
| 28 Finder that locates files based on entries in a file matched by a |
| 29 regular expression. |
| 30 """ |
| 31 |
| 32 def __init__(self, path, pattern, postproc=lambda x: x): |
| 33 self.pattern = pattern |
| 34 self.postproc = postproc |
| 35 self.entries_path = convert_path(path) |
| 36 |
| 37 def _finder(self, dirname, filename): |
| 38 f = open(filename, 'rU') |
| 39 try: |
| 40 data = f.read() |
| 41 finally: |
| 42 f.close() |
| 43 for match in self.pattern.finditer(data): |
| 44 path = match.group(1) |
| 45 # postproc was formerly used when the svn finder |
| 46 # was an re_finder for calling unescape |
| 47 path = self.postproc(path) |
| 48 yield svn_utils.joinpath(dirname, path) |
| 49 |
| 50 def find(self, dirname=''): |
| 51 path = svn_utils.joinpath(dirname, self.entries_path) |
| 52 |
| 53 if not os.path.isfile(path): |
| 54 # entries file doesn't exist |
| 55 return |
| 56 for path in self._finder(dirname, path): |
| 57 if os.path.isfile(path): |
| 58 yield path |
| 59 elif os.path.isdir(path): |
| 60 for item in self.find(path): |
| 61 yield item |
| 62 |
| 63 __call__ = find |
| 64 |
| 65 |
| 66 def _default_revctrl(dirname=''): |
| 67 'Primary svn_cvs entry point' |
| 68 for finder in finders: |
| 69 for item in finder(dirname): |
| 70 yield item |
| 71 |
| 72 |
| 73 finders = [ |
| 74 re_finder('CVS/Entries', re.compile(r"^\w?/([^/]+)/", re.M)), |
| 75 svn_utils.svn_finder, |
| 76 ] |
| 77 |
| 78 |
| 79 class sdist(orig.sdist): |
| 80 """Smart sdist that finds anything supported by revision control""" |
| 81 |
| 82 user_options = [ |
| 83 ('formats=', None, |
| 84 "formats for source distribution (comma-separated list)"), |
| 85 ('keep-temp', 'k', |
| 86 "keep the distribution tree around after creating " + |
| 87 "archive file(s)"), |
| 88 ('dist-dir=', 'd', |
| 89 "directory to put the source distribution archive(s) in " |
| 90 "[default: dist]"), |
| 91 ] |
| 92 |
| 93 negative_opt = {} |
| 94 |
| 95 def run(self): |
| 96 self.run_command('egg_info') |
| 97 ei_cmd = self.get_finalized_command('egg_info') |
| 98 self.filelist = ei_cmd.filelist |
| 99 self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt')) |
| 100 self.check_readme() |
| 101 |
| 102 # Run sub commands |
| 103 for cmd_name in self.get_sub_commands(): |
| 104 self.run_command(cmd_name) |
| 105 |
| 106 # Call check_metadata only if no 'check' command |
| 107 # (distutils <= 2.6) |
| 108 import distutils.command |
| 109 |
| 110 if 'check' not in distutils.command.__all__: |
| 111 self.check_metadata() |
| 112 |
| 113 self.make_distribution() |
| 114 |
| 115 dist_files = getattr(self.distribution, 'dist_files', []) |
| 116 for file in self.archive_files: |
| 117 data = ('sdist', '', file) |
| 118 if data not in dist_files: |
| 119 dist_files.append(data) |
| 120 |
| 121 def __read_template_hack(self): |
| 122 # This grody hack closes the template file (MANIFEST.in) if an |
| 123 # exception occurs during read_template. |
| 124 # Doing so prevents an error when easy_install attempts to delete the |
| 125 # file. |
| 126 try: |
| 127 orig.sdist.read_template(self) |
| 128 except: |
| 129 sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close() |
| 130 raise |
| 131 |
| 132 # Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle |
| 133 # has been fixed, so only override the method if we're using an earlier |
| 134 # Python. |
| 135 has_leaky_handle = ( |
| 136 sys.version_info < (2, 7, 2) |
| 137 or (3, 0) <= sys.version_info < (3, 1, 4) |
| 138 or (3, 2) <= sys.version_info < (3, 2, 1) |
| 139 ) |
| 140 if has_leaky_handle: |
| 141 read_template = __read_template_hack |
| 142 |
| 143 def add_defaults(self): |
| 144 standards = [READMES, |
| 145 self.distribution.script_name] |
| 146 for fn in standards: |
| 147 if isinstance(fn, tuple): |
| 148 alts = fn |
| 149 got_it = 0 |
| 150 for fn in alts: |
| 151 if cs_path_exists(fn): |
| 152 got_it = 1 |
| 153 self.filelist.append(fn) |
| 154 break |
| 155 |
| 156 if not got_it: |
| 157 self.warn("standard file not found: should have one of " + |
| 158 ', '.join(alts)) |
| 159 else: |
| 160 if cs_path_exists(fn): |
| 161 self.filelist.append(fn) |
| 162 else: |
| 163 self.warn("standard file '%s' not found" % fn) |
| 164 |
| 165 optional = ['test/test*.py', 'setup.cfg'] |
| 166 for pattern in optional: |
| 167 files = list(filter(cs_path_exists, glob(pattern))) |
| 168 if files: |
| 169 self.filelist.extend(files) |
| 170 |
| 171 # getting python files |
| 172 if self.distribution.has_pure_modules(): |
| 173 build_py = self.get_finalized_command('build_py') |
| 174 self.filelist.extend(build_py.get_source_files()) |
| 175 # This functionality is incompatible with include_package_data, and |
| 176 # will in fact create an infinite recursion if include_package_data |
| 177 # is True. Use of include_package_data will imply that |
| 178 # distutils-style automatic handling of package_data is disabled |
| 179 if not self.distribution.include_package_data: |
| 180 for _, src_dir, _, filenames in build_py.data_files: |
| 181 self.filelist.extend([os.path.join(src_dir, filename) |
| 182 for filename in filenames]) |
| 183 |
| 184 if self.distribution.has_ext_modules(): |
| 185 build_ext = self.get_finalized_command('build_ext') |
| 186 self.filelist.extend(build_ext.get_source_files()) |
| 187 |
| 188 if self.distribution.has_c_libraries(): |
| 189 build_clib = self.get_finalized_command('build_clib') |
| 190 self.filelist.extend(build_clib.get_source_files()) |
| 191 |
| 192 if self.distribution.has_scripts(): |
| 193 build_scripts = self.get_finalized_command('build_scripts') |
| 194 self.filelist.extend(build_scripts.get_source_files()) |
| 195 |
| 196 def check_readme(self): |
| 197 for f in READMES: |
| 198 if os.path.exists(f): |
| 199 return |
| 200 else: |
| 201 self.warn( |
| 202 "standard file not found: should have one of " + |
| 203 ', '.join(READMES) |
| 204 ) |
| 205 |
| 206 def make_release_tree(self, base_dir, files): |
| 207 orig.sdist.make_release_tree(self, base_dir, files) |
| 208 |
| 209 # Save any egg_info command line options used to create this sdist |
| 210 dest = os.path.join(base_dir, 'setup.cfg') |
| 211 if hasattr(os, 'link') and os.path.exists(dest): |
| 212 # unlink and re-copy, since it might be hard-linked, and |
| 213 # we don't want to change the source version |
| 214 os.unlink(dest) |
| 215 self.copy_file('setup.cfg', dest) |
| 216 |
| 217 self.get_finalized_command('egg_info').save_version_info(dest) |
| 218 |
| 219 def _manifest_is_not_generated(self): |
| 220 # check for special comment used in 2.7.1 and higher |
| 221 if not os.path.isfile(self.manifest): |
| 222 return False |
| 223 |
| 224 fp = open(self.manifest, 'rbU') |
| 225 try: |
| 226 first_line = fp.readline() |
| 227 finally: |
| 228 fp.close() |
| 229 return (first_line != |
| 230 '# file GENERATED by distutils, do NOT edit\n'.encode()) |
| 231 |
| 232 def read_manifest(self): |
| 233 """Read the manifest file (named by 'self.manifest') and use it to |
| 234 fill in 'self.filelist', the list of files to include in the source |
| 235 distribution. |
| 236 """ |
| 237 log.info("reading manifest file '%s'", self.manifest) |
| 238 manifest = open(self.manifest, 'rbU') |
| 239 for line in manifest: |
| 240 # The manifest must contain UTF-8. See #303. |
| 241 if PY3: |
| 242 try: |
| 243 line = line.decode('UTF-8') |
| 244 except UnicodeDecodeError: |
| 245 log.warn("%r not UTF-8 decodable -- skipping" % line) |
| 246 continue |
| 247 # ignore comments and blank lines |
| 248 line = line.strip() |
| 249 if line.startswith('#') or not line: |
| 250 continue |
| 251 self.filelist.append(line) |
| 252 manifest.close() |
OLD | NEW |