Mercurial > repos > bcclaywell > argo_navis
comparison venv/lib/python2.7/site-packages/setuptools/command/egg_info.py @ 0:d67268158946 draft
planemo upload commit a3f181f5f126803c654b3a66dd4e83a48f7e203b
author | bcclaywell |
---|---|
date | Mon, 12 Oct 2015 17:43:33 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d67268158946 |
---|---|
1 """setuptools.command.egg_info | |
2 | |
3 Create a distribution's .egg-info directory and contents""" | |
4 | |
5 from distutils.filelist import FileList as _FileList | |
6 from distutils.util import convert_path | |
7 from distutils import log | |
8 import distutils.errors | |
9 import distutils.filelist | |
10 import os | |
11 import re | |
12 import sys | |
13 | |
14 try: | |
15 from setuptools_svn import svn_utils | |
16 except ImportError: | |
17 pass | |
18 | |
19 from setuptools import Command | |
20 from setuptools.command.sdist import sdist | |
21 from setuptools.compat import basestring, PY3, StringIO | |
22 from setuptools.command.sdist import walk_revctrl | |
23 from pkg_resources import ( | |
24 parse_requirements, safe_name, parse_version, | |
25 safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename) | |
26 import setuptools.unicode_utils as unicode_utils | |
27 | |
28 from pkg_resources import packaging | |
29 | |
30 class egg_info(Command): | |
31 description = "create a distribution's .egg-info directory" | |
32 | |
33 user_options = [ | |
34 ('egg-base=', 'e', "directory containing .egg-info directories" | |
35 " (default: top of the source tree)"), | |
36 ('tag-svn-revision', 'r', | |
37 "Add subversion revision ID to version number"), | |
38 ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"), | |
39 ('tag-build=', 'b', "Specify explicit tag to add to version number"), | |
40 ('no-svn-revision', 'R', | |
41 "Don't add subversion revision ID [default]"), | |
42 ('no-date', 'D', "Don't include date stamp [default]"), | |
43 ] | |
44 | |
45 boolean_options = ['tag-date', 'tag-svn-revision'] | |
46 negative_opt = {'no-svn-revision': 'tag-svn-revision', | |
47 'no-date': 'tag-date'} | |
48 | |
49 def initialize_options(self): | |
50 self.egg_name = None | |
51 self.egg_version = None | |
52 self.egg_base = None | |
53 self.egg_info = None | |
54 self.tag_build = None | |
55 self.tag_svn_revision = 0 | |
56 self.tag_date = 0 | |
57 self.broken_egg_info = False | |
58 self.vtags = None | |
59 | |
60 def save_version_info(self, filename): | |
61 from setuptools.command.setopt import edit_config | |
62 | |
63 values = dict( | |
64 egg_info=dict( | |
65 tag_svn_revision=0, | |
66 tag_date=0, | |
67 tag_build=self.tags(), | |
68 ) | |
69 ) | |
70 edit_config(filename, values) | |
71 | |
72 def finalize_options(self): | |
73 self.egg_name = safe_name(self.distribution.get_name()) | |
74 self.vtags = self.tags() | |
75 self.egg_version = self.tagged_version() | |
76 | |
77 parsed_version = parse_version(self.egg_version) | |
78 | |
79 try: | |
80 is_version = isinstance(parsed_version, packaging.version.Version) | |
81 spec = ( | |
82 "%s==%s" if is_version else "%s===%s" | |
83 ) | |
84 list( | |
85 parse_requirements(spec % (self.egg_name, self.egg_version)) | |
86 ) | |
87 except ValueError: | |
88 raise distutils.errors.DistutilsOptionError( | |
89 "Invalid distribution name or version syntax: %s-%s" % | |
90 (self.egg_name, self.egg_version) | |
91 ) | |
92 | |
93 if self.egg_base is None: | |
94 dirs = self.distribution.package_dir | |
95 self.egg_base = (dirs or {}).get('', os.curdir) | |
96 | |
97 self.ensure_dirname('egg_base') | |
98 self.egg_info = to_filename(self.egg_name) + '.egg-info' | |
99 if self.egg_base != os.curdir: | |
100 self.egg_info = os.path.join(self.egg_base, self.egg_info) | |
101 if '-' in self.egg_name: | |
102 self.check_broken_egg_info() | |
103 | |
104 # Set package version for the benefit of dumber commands | |
105 # (e.g. sdist, bdist_wininst, etc.) | |
106 # | |
107 self.distribution.metadata.version = self.egg_version | |
108 | |
109 # If we bootstrapped around the lack of a PKG-INFO, as might be the | |
110 # case in a fresh checkout, make sure that any special tags get added | |
111 # to the version info | |
112 # | |
113 pd = self.distribution._patched_dist | |
114 if pd is not None and pd.key == self.egg_name.lower(): | |
115 pd._version = self.egg_version | |
116 pd._parsed_version = parse_version(self.egg_version) | |
117 self.distribution._patched_dist = None | |
118 | |
119 def write_or_delete_file(self, what, filename, data, force=False): | |
120 """Write `data` to `filename` or delete if empty | |
121 | |
122 If `data` is non-empty, this routine is the same as ``write_file()``. | |
123 If `data` is empty but not ``None``, this is the same as calling | |
124 ``delete_file(filename)`. If `data` is ``None``, then this is a no-op | |
125 unless `filename` exists, in which case a warning is issued about the | |
126 orphaned file (if `force` is false), or deleted (if `force` is true). | |
127 """ | |
128 if data: | |
129 self.write_file(what, filename, data) | |
130 elif os.path.exists(filename): | |
131 if data is None and not force: | |
132 log.warn( | |
133 "%s not set in setup(), but %s exists", what, filename | |
134 ) | |
135 return | |
136 else: | |
137 self.delete_file(filename) | |
138 | |
139 def write_file(self, what, filename, data): | |
140 """Write `data` to `filename` (if not a dry run) after announcing it | |
141 | |
142 `what` is used in a log message to identify what is being written | |
143 to the file. | |
144 """ | |
145 log.info("writing %s to %s", what, filename) | |
146 if PY3: | |
147 data = data.encode("utf-8") | |
148 if not self.dry_run: | |
149 f = open(filename, 'wb') | |
150 f.write(data) | |
151 f.close() | |
152 | |
153 def delete_file(self, filename): | |
154 """Delete `filename` (if not a dry run) after announcing it""" | |
155 log.info("deleting %s", filename) | |
156 if not self.dry_run: | |
157 os.unlink(filename) | |
158 | |
159 def tagged_version(self): | |
160 version = self.distribution.get_version() | |
161 # egg_info may be called more than once for a distribution, | |
162 # in which case the version string already contains all tags. | |
163 if self.vtags and version.endswith(self.vtags): | |
164 return safe_version(version) | |
165 return safe_version(version + self.vtags) | |
166 | |
167 def run(self): | |
168 self.mkpath(self.egg_info) | |
169 installer = self.distribution.fetch_build_egg | |
170 for ep in iter_entry_points('egg_info.writers'): | |
171 ep.require(installer=installer) | |
172 writer = ep.resolve() | |
173 writer(self, ep.name, os.path.join(self.egg_info, ep.name)) | |
174 | |
175 # Get rid of native_libs.txt if it was put there by older bdist_egg | |
176 nl = os.path.join(self.egg_info, "native_libs.txt") | |
177 if os.path.exists(nl): | |
178 self.delete_file(nl) | |
179 | |
180 self.find_sources() | |
181 | |
182 def tags(self): | |
183 version = '' | |
184 if self.tag_build: | |
185 version += self.tag_build | |
186 if self.tag_svn_revision: | |
187 rev = self.get_svn_revision() | |
188 if rev: # is 0 if it's not an svn working copy | |
189 version += '-r%s' % rev | |
190 if self.tag_date: | |
191 import time | |
192 | |
193 version += time.strftime("-%Y%m%d") | |
194 return version | |
195 | |
196 @staticmethod | |
197 def get_svn_revision(): | |
198 if 'svn_utils' not in globals(): | |
199 return "0" | |
200 return str(svn_utils.SvnInfo.load(os.curdir).get_revision()) | |
201 | |
202 def find_sources(self): | |
203 """Generate SOURCES.txt manifest file""" | |
204 manifest_filename = os.path.join(self.egg_info, "SOURCES.txt") | |
205 mm = manifest_maker(self.distribution) | |
206 mm.manifest = manifest_filename | |
207 mm.run() | |
208 self.filelist = mm.filelist | |
209 | |
210 def check_broken_egg_info(self): | |
211 bei = self.egg_name + '.egg-info' | |
212 if self.egg_base != os.curdir: | |
213 bei = os.path.join(self.egg_base, bei) | |
214 if os.path.exists(bei): | |
215 log.warn( | |
216 "-" * 78 + '\n' | |
217 "Note: Your current .egg-info directory has a '-' in its name;" | |
218 '\nthis will not work correctly with "setup.py develop".\n\n' | |
219 'Please rename %s to %s to correct this problem.\n' + '-' * 78, | |
220 bei, self.egg_info | |
221 ) | |
222 self.broken_egg_info = self.egg_info | |
223 self.egg_info = bei # make it work for now | |
224 | |
225 | |
226 class FileList(_FileList): | |
227 """File list that accepts only existing, platform-independent paths""" | |
228 | |
229 def append(self, item): | |
230 if item.endswith('\r'): # Fix older sdists built on Windows | |
231 item = item[:-1] | |
232 path = convert_path(item) | |
233 | |
234 if self._safe_path(path): | |
235 self.files.append(path) | |
236 | |
237 def extend(self, paths): | |
238 self.files.extend(filter(self._safe_path, paths)) | |
239 | |
240 def _repair(self): | |
241 """ | |
242 Replace self.files with only safe paths | |
243 | |
244 Because some owners of FileList manipulate the underlying | |
245 ``files`` attribute directly, this method must be called to | |
246 repair those paths. | |
247 """ | |
248 self.files = list(filter(self._safe_path, self.files)) | |
249 | |
250 def _safe_path(self, path): | |
251 enc_warn = "'%s' not %s encodable -- skipping" | |
252 | |
253 # To avoid accidental trans-codings errors, first to unicode | |
254 u_path = unicode_utils.filesys_decode(path) | |
255 if u_path is None: | |
256 log.warn("'%s' in unexpected encoding -- skipping" % path) | |
257 return False | |
258 | |
259 # Must ensure utf-8 encodability | |
260 utf8_path = unicode_utils.try_encode(u_path, "utf-8") | |
261 if utf8_path is None: | |
262 log.warn(enc_warn, path, 'utf-8') | |
263 return False | |
264 | |
265 try: | |
266 # accept is either way checks out | |
267 if os.path.exists(u_path) or os.path.exists(utf8_path): | |
268 return True | |
269 # this will catch any encode errors decoding u_path | |
270 except UnicodeEncodeError: | |
271 log.warn(enc_warn, path, sys.getfilesystemencoding()) | |
272 | |
273 | |
274 class manifest_maker(sdist): | |
275 template = "MANIFEST.in" | |
276 | |
277 def initialize_options(self): | |
278 self.use_defaults = 1 | |
279 self.prune = 1 | |
280 self.manifest_only = 1 | |
281 self.force_manifest = 1 | |
282 | |
283 def finalize_options(self): | |
284 pass | |
285 | |
286 def run(self): | |
287 self.filelist = FileList() | |
288 if not os.path.exists(self.manifest): | |
289 self.write_manifest() # it must exist so it'll get in the list | |
290 self.filelist.findall() | |
291 self.add_defaults() | |
292 if os.path.exists(self.template): | |
293 self.read_template() | |
294 self.prune_file_list() | |
295 self.filelist.sort() | |
296 self.filelist.remove_duplicates() | |
297 self.write_manifest() | |
298 | |
299 def _manifest_normalize(self, path): | |
300 path = unicode_utils.filesys_decode(path) | |
301 return path.replace(os.sep, '/') | |
302 | |
303 def write_manifest(self): | |
304 """ | |
305 Write the file list in 'self.filelist' to the manifest file | |
306 named by 'self.manifest'. | |
307 """ | |
308 self.filelist._repair() | |
309 | |
310 # Now _repairs should encodability, but not unicode | |
311 files = [self._manifest_normalize(f) for f in self.filelist.files] | |
312 msg = "writing manifest file '%s'" % self.manifest | |
313 self.execute(write_file, (self.manifest, files), msg) | |
314 | |
315 def warn(self, msg): # suppress missing-file warnings from sdist | |
316 if not msg.startswith("standard file not found:"): | |
317 sdist.warn(self, msg) | |
318 | |
319 def add_defaults(self): | |
320 sdist.add_defaults(self) | |
321 self.filelist.append(self.template) | |
322 self.filelist.append(self.manifest) | |
323 rcfiles = list(walk_revctrl()) | |
324 if rcfiles: | |
325 self.filelist.extend(rcfiles) | |
326 elif os.path.exists(self.manifest): | |
327 self.read_manifest() | |
328 ei_cmd = self.get_finalized_command('egg_info') | |
329 self._add_egg_info(cmd=ei_cmd) | |
330 self.filelist.include_pattern("*", prefix=ei_cmd.egg_info) | |
331 | |
332 def _add_egg_info(self, cmd): | |
333 """ | |
334 Add paths for egg-info files for an external egg-base. | |
335 | |
336 The egg-info files are written to egg-base. If egg-base is | |
337 outside the current working directory, this method | |
338 searchs the egg-base directory for files to include | |
339 in the manifest. Uses distutils.filelist.findall (which is | |
340 really the version monkeypatched in by setuptools/__init__.py) | |
341 to perform the search. | |
342 | |
343 Since findall records relative paths, prefix the returned | |
344 paths with cmd.egg_base, so add_default's include_pattern call | |
345 (which is looking for the absolute cmd.egg_info) will match | |
346 them. | |
347 """ | |
348 if cmd.egg_base == os.curdir: | |
349 # egg-info files were already added by something else | |
350 return | |
351 | |
352 discovered = distutils.filelist.findall(cmd.egg_base) | |
353 resolved = (os.path.join(cmd.egg_base, path) for path in discovered) | |
354 self.filelist.allfiles.extend(resolved) | |
355 | |
356 def prune_file_list(self): | |
357 build = self.get_finalized_command('build') | |
358 base_dir = self.distribution.get_fullname() | |
359 self.filelist.exclude_pattern(None, prefix=build.build_base) | |
360 self.filelist.exclude_pattern(None, prefix=base_dir) | |
361 sep = re.escape(os.sep) | |
362 self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep, | |
363 is_regex=1) | |
364 | |
365 | |
366 def write_file(filename, contents): | |
367 """Create a file with the specified name and write 'contents' (a | |
368 sequence of strings without line terminators) to it. | |
369 """ | |
370 contents = "\n".join(contents) | |
371 | |
372 # assuming the contents has been vetted for utf-8 encoding | |
373 contents = contents.encode("utf-8") | |
374 | |
375 with open(filename, "wb") as f: # always write POSIX-style manifest | |
376 f.write(contents) | |
377 | |
378 | |
379 def write_pkg_info(cmd, basename, filename): | |
380 log.info("writing %s", filename) | |
381 if not cmd.dry_run: | |
382 metadata = cmd.distribution.metadata | |
383 metadata.version, oldver = cmd.egg_version, metadata.version | |
384 metadata.name, oldname = cmd.egg_name, metadata.name | |
385 try: | |
386 # write unescaped data to PKG-INFO, so older pkg_resources | |
387 # can still parse it | |
388 metadata.write_pkg_info(cmd.egg_info) | |
389 finally: | |
390 metadata.name, metadata.version = oldname, oldver | |
391 | |
392 safe = getattr(cmd.distribution, 'zip_safe', None) | |
393 from setuptools.command import bdist_egg | |
394 | |
395 bdist_egg.write_safety_flag(cmd.egg_info, safe) | |
396 | |
397 | |
398 def warn_depends_obsolete(cmd, basename, filename): | |
399 if os.path.exists(filename): | |
400 log.warn( | |
401 "WARNING: 'depends.txt' is not used by setuptools 0.6!\n" | |
402 "Use the install_requires/extras_require setup() args instead." | |
403 ) | |
404 | |
405 | |
406 def _write_requirements(stream, reqs): | |
407 lines = yield_lines(reqs or ()) | |
408 append_cr = lambda line: line + '\n' | |
409 lines = map(append_cr, lines) | |
410 stream.writelines(lines) | |
411 | |
412 | |
413 def write_requirements(cmd, basename, filename): | |
414 dist = cmd.distribution | |
415 data = StringIO() | |
416 _write_requirements(data, dist.install_requires) | |
417 extras_require = dist.extras_require or {} | |
418 for extra in sorted(extras_require): | |
419 data.write('\n[{extra}]\n'.format(**vars())) | |
420 _write_requirements(data, extras_require[extra]) | |
421 cmd.write_or_delete_file("requirements", filename, data.getvalue()) | |
422 | |
423 | |
424 def write_setup_requirements(cmd, basename, filename): | |
425 data = StringIO() | |
426 _write_requirements(data, cmd.distribution.setup_requires) | |
427 cmd.write_or_delete_file("setup-requirements", filename, data.getvalue()) | |
428 | |
429 | |
430 def write_toplevel_names(cmd, basename, filename): | |
431 pkgs = dict.fromkeys( | |
432 [ | |
433 k.split('.', 1)[0] | |
434 for k in cmd.distribution.iter_distribution_names() | |
435 ] | |
436 ) | |
437 cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n') | |
438 | |
439 | |
440 def overwrite_arg(cmd, basename, filename): | |
441 write_arg(cmd, basename, filename, True) | |
442 | |
443 | |
444 def write_arg(cmd, basename, filename, force=False): | |
445 argname = os.path.splitext(basename)[0] | |
446 value = getattr(cmd.distribution, argname, None) | |
447 if value is not None: | |
448 value = '\n'.join(value) + '\n' | |
449 cmd.write_or_delete_file(argname, filename, value, force) | |
450 | |
451 | |
452 def write_entries(cmd, basename, filename): | |
453 ep = cmd.distribution.entry_points | |
454 | |
455 if isinstance(ep, basestring) or ep is None: | |
456 data = ep | |
457 elif ep is not None: | |
458 data = [] | |
459 for section, contents in sorted(ep.items()): | |
460 if not isinstance(contents, basestring): | |
461 contents = EntryPoint.parse_group(section, contents) | |
462 contents = '\n'.join(sorted(map(str, contents.values()))) | |
463 data.append('[%s]\n%s\n\n' % (section, contents)) | |
464 data = ''.join(data) | |
465 | |
466 cmd.write_or_delete_file('entry points', filename, data, True) | |
467 | |
468 | |
469 def get_pkg_info_revision(): | |
470 # See if we can get a -r### off of PKG-INFO, in case this is an sdist of | |
471 # a subversion revision | |
472 # | |
473 if os.path.exists('PKG-INFO'): | |
474 f = open('PKG-INFO', 'rU') | |
475 for line in f: | |
476 match = re.match(r"Version:.*-r(\d+)\s*$", line) | |
477 if match: | |
478 return int(match.group(1)) | |
479 f.close() | |
480 return 0 |