root / env / lib / python2.7 / site-packages / distribute-0.6.19-py2.7.egg / setuptools / command / easy_install.py @ 1a305335
History | View | Annotate | Download (68.5 KB)
1 | 1a305335 | officers | #!python
|
---|---|---|---|
2 | """\
|
||
3 | Easy Install
|
||
4 | ------------
|
||
5 |
|
||
6 | A tool for doing automatic download/extract/build of distutils-based Python
|
||
7 | packages. For detailed documentation, see the accompanying EasyInstall.txt
|
||
8 | file, or visit the `EasyInstall home page`__.
|
||
9 |
|
||
10 | __ http://packages.python.org/distribute/easy_install.html
|
||
11 |
|
||
12 | """
|
||
13 | import sys, os.path, zipimport, shutil, tempfile, zipfile, re, stat, random |
||
14 | from glob import glob |
||
15 | from setuptools import Command, _dont_write_bytecode |
||
16 | from setuptools.sandbox import run_setup |
||
17 | from distutils import log, dir_util |
||
18 | from distutils.util import get_platform |
||
19 | from distutils.util import convert_path, subst_vars |
||
20 | from distutils.sysconfig import get_python_lib, get_config_vars |
||
21 | from distutils.errors import DistutilsArgError, DistutilsOptionError, \ |
||
22 | DistutilsError, DistutilsPlatformError |
||
23 | from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS |
||
24 | from setuptools.archive_util import unpack_archive |
||
25 | from setuptools.package_index import PackageIndex |
||
26 | from setuptools.package_index import URL_SCHEME |
||
27 | from setuptools.command import bdist_egg, egg_info |
||
28 | from pkg_resources import yield_lines, normalize_path, resource_string, \ |
||
29 | ensure_directory, get_distribution, find_distributions, \ |
||
30 | Environment, Requirement, Distribution, \ |
||
31 | PathMetadata, EggMetadata, WorkingSet, \ |
||
32 | DistributionNotFound, VersionConflict, \ |
||
33 | DEVELOP_DIST
|
||
34 | |||
35 | sys_executable = os.path.normpath(sys.executable) |
||
36 | |||
37 | __all__ = [ |
||
38 | 'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg', |
||
39 | 'main', 'get_exe_prefixes', |
||
40 | ] |
||
41 | |||
42 | import site |
||
43 | HAS_USER_SITE = not sys.version < "2.6" and site.ENABLE_USER_SITE |
||
44 | |||
45 | def samefile(p1,p2): |
||
46 | if hasattr(os.path,'samefile') and ( |
||
47 | os.path.exists(p1) and os.path.exists(p2)
|
||
48 | ): |
||
49 | return os.path.samefile(p1,p2)
|
||
50 | return (
|
||
51 | os.path.normpath(os.path.normcase(p1)) == |
||
52 | os.path.normpath(os.path.normcase(p2)) |
||
53 | ) |
||
54 | |||
55 | if sys.version_info <= (3,): |
||
56 | def _to_ascii(s): |
||
57 | return s
|
||
58 | def isascii(s): |
||
59 | try:
|
||
60 | unicode(s, 'ascii') |
||
61 | return True |
||
62 | except UnicodeError: |
||
63 | return False |
||
64 | else:
|
||
65 | def _to_ascii(s): |
||
66 | return s.encode('ascii') |
||
67 | def isascii(s): |
||
68 | try:
|
||
69 | s.encode('ascii')
|
||
70 | return True |
||
71 | except UnicodeError: |
||
72 | return False |
||
73 | |||
74 | class easy_install(Command): |
||
75 | """Manage a download/build/install process"""
|
||
76 | description = "Find/get/install Python packages"
|
||
77 | command_consumes_arguments = True
|
||
78 | |||
79 | user_options = [ |
||
80 | ('prefix=', None, "installation prefix"), |
||
81 | ("zip-ok", "z", "install package as a zipfile"), |
||
82 | ("multi-version", "m", "make apps have to require() a version"), |
||
83 | ("upgrade", "U", "force upgrade (searches PyPI for latest versions)"), |
||
84 | ("install-dir=", "d", "install package to DIR"), |
||
85 | ("script-dir=", "s", "install scripts to DIR"), |
||
86 | ("exclude-scripts", "x", "Don't install scripts"), |
||
87 | ("always-copy", "a", "Copy all needed packages to install dir"), |
||
88 | ("index-url=", "i", "base URL of Python Package Index"), |
||
89 | ("find-links=", "f", "additional URL(s) to search for packages"), |
||
90 | ("delete-conflicting", "D", "no longer needed; don't use this"), |
||
91 | ("ignore-conflicts-at-my-risk", None, |
||
92 | "no longer needed; don't use this"),
|
||
93 | ("build-directory=", "b", |
||
94 | "download/extract/build in DIR; keep the results"),
|
||
95 | ('optimize=', 'O', |
||
96 | "also compile with optimization: -O1 for \"python -O\", "
|
||
97 | "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
|
||
98 | ('record=', None, |
||
99 | "filename in which to record list of installed files"),
|
||
100 | ('always-unzip', 'Z', "don't install as a zipfile, no matter what"), |
||
101 | ('site-dirs=','S',"list of directories where .pth files work"), |
||
102 | ('editable', 'e', "Install specified packages in editable form"), |
||
103 | ('no-deps', 'N', "don't install dependencies"), |
||
104 | ('allow-hosts=', 'H', "pattern(s) that hostnames must match"), |
||
105 | ('local-snapshots-ok', 'l', "allow building eggs from local checkouts"), |
||
106 | ('version', None, "print version information and exit"), |
||
107 | ('no-find-links', None, |
||
108 | "Don't load find-links defined in packages being installed")
|
||
109 | ] |
||
110 | boolean_options = [ |
||
111 | 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', |
||
112 | 'delete-conflicting', 'ignore-conflicts-at-my-risk', 'editable', |
||
113 | 'no-deps', 'local-snapshots-ok', 'version' |
||
114 | ] |
||
115 | |||
116 | if HAS_USER_SITE:
|
||
117 | user_options.append(('user', None, |
||
118 | "install in user site-package '%s'" % site.USER_SITE))
|
||
119 | boolean_options.append('user')
|
||
120 | |||
121 | |||
122 | negative_opt = {'always-unzip': 'zip-ok'} |
||
123 | create_index = PackageIndex |
||
124 | |||
125 | def initialize_options(self): |
||
126 | if HAS_USER_SITE:
|
||
127 | whereami = os.path.abspath(__file__) |
||
128 | self.user = whereami.startswith(site.USER_SITE)
|
||
129 | else:
|
||
130 | self.user = 0 |
||
131 | |||
132 | self.zip_ok = self.local_snapshots_ok = None |
||
133 | self.install_dir = self.script_dir = self.exclude_scripts = None |
||
134 | self.index_url = None |
||
135 | self.find_links = None |
||
136 | self.build_directory = None |
||
137 | self.args = None |
||
138 | self.optimize = self.record = None |
||
139 | self.upgrade = self.always_copy = self.multi_version = None |
||
140 | self.editable = self.no_deps = self.allow_hosts = None |
||
141 | self.root = self.prefix = self.no_report = None |
||
142 | self.version = None |
||
143 | self.install_purelib = None # for pure module distributions |
||
144 | self.install_platlib = None # non-pure (dists w/ extensions) |
||
145 | self.install_headers = None # for C/C++ headers |
||
146 | self.install_lib = None # set to either purelib or platlib |
||
147 | self.install_scripts = None |
||
148 | self.install_data = None |
||
149 | self.install_base = None |
||
150 | self.install_platbase = None |
||
151 | if HAS_USER_SITE:
|
||
152 | self.install_userbase = site.USER_BASE
|
||
153 | self.install_usersite = site.USER_SITE
|
||
154 | else:
|
||
155 | self.install_userbase = None |
||
156 | self.install_usersite = None |
||
157 | self.no_find_links = None |
||
158 | |||
159 | # Options not specifiable via command line
|
||
160 | self.package_index = None |
||
161 | self.pth_file = self.always_copy_from = None |
||
162 | self.delete_conflicting = None |
||
163 | self.ignore_conflicts_at_my_risk = None |
||
164 | self.site_dirs = None |
||
165 | self.installed_projects = {}
|
||
166 | self.sitepy_installed = False |
||
167 | # Always read easy_install options, even if we are subclassed, or have
|
||
168 | # an independent instance created. This ensures that defaults will
|
||
169 | # always come from the standard configuration file(s)' "easy_install"
|
||
170 | # section, even if this is a "develop" or "install" command, or some
|
||
171 | # other embedding.
|
||
172 | self._dry_run = None |
||
173 | self.verbose = self.distribution.verbose |
||
174 | self.distribution._set_command_options(
|
||
175 | self, self.distribution.get_option_dict('easy_install') |
||
176 | ) |
||
177 | |||
178 | def delete_blockers(self, blockers): |
||
179 | for filename in blockers: |
||
180 | if os.path.exists(filename) or os.path.islink(filename): |
||
181 | log.info("Deleting %s", filename)
|
||
182 | if not self.dry_run: |
||
183 | if os.path.isdir(filename) and not os.path.islink(filename): |
||
184 | rmtree(filename) |
||
185 | else:
|
||
186 | os.unlink(filename) |
||
187 | |||
188 | def finalize_options(self): |
||
189 | if self.version: |
||
190 | print 'distribute %s' % get_distribution('distribute').version |
||
191 | sys.exit() |
||
192 | |||
193 | py_version = sys.version.split()[0]
|
||
194 | prefix, exec_prefix = get_config_vars('prefix', 'exec_prefix') |
||
195 | |||
196 | self.config_vars = {'dist_name': self.distribution.get_name(), |
||
197 | 'dist_version': self.distribution.get_version(), |
||
198 | 'dist_fullname': self.distribution.get_fullname(), |
||
199 | 'py_version': py_version,
|
||
200 | 'py_version_short': py_version[0:3], |
||
201 | 'py_version_nodot': py_version[0] + py_version[2], |
||
202 | 'sys_prefix': prefix,
|
||
203 | 'prefix': prefix,
|
||
204 | 'sys_exec_prefix': exec_prefix,
|
||
205 | 'exec_prefix': exec_prefix,
|
||
206 | # Only python 3.2+ has abiflags
|
||
207 | 'abiflags': getattr(sys, 'abiflags', ''), |
||
208 | } |
||
209 | |||
210 | if HAS_USER_SITE:
|
||
211 | self.config_vars['userbase'] = self.install_userbase |
||
212 | self.config_vars['usersite'] = self.install_usersite |
||
213 | |||
214 | # fix the install_dir if "--user" was used
|
||
215 | #XXX: duplicate of the code in the setup command
|
||
216 | if self.user and HAS_USER_SITE: |
||
217 | self.create_home_path()
|
||
218 | if self.install_userbase is None: |
||
219 | raise DistutilsPlatformError(
|
||
220 | "User base directory is not specified")
|
||
221 | self.install_base = self.install_platbase = self.install_userbase |
||
222 | if os.name == 'posix': |
||
223 | self.select_scheme("unix_user") |
||
224 | else:
|
||
225 | self.select_scheme(os.name + "_user") |
||
226 | |||
227 | self.expand_basedirs()
|
||
228 | self.expand_dirs()
|
||
229 | |||
230 | self._expand('install_dir','script_dir','build_directory','site_dirs') |
||
231 | # If a non-default installation directory was specified, default the
|
||
232 | # script directory to match it.
|
||
233 | if self.script_dir is None: |
||
234 | self.script_dir = self.install_dir |
||
235 | |||
236 | if self.no_find_links is None: |
||
237 | self.no_find_links = False |
||
238 | |||
239 | # Let install_dir get set by install_lib command, which in turn
|
||
240 | # gets its info from the install command, and takes into account
|
||
241 | # --prefix and --home and all that other crud.
|
||
242 | self.set_undefined_options('install_lib', |
||
243 | ('install_dir','install_dir') |
||
244 | ) |
||
245 | # Likewise, set default script_dir from 'install_scripts.install_dir'
|
||
246 | self.set_undefined_options('install_scripts', |
||
247 | ('install_dir', 'script_dir') |
||
248 | ) |
||
249 | |||
250 | if self.user and self.install_purelib: |
||
251 | self.install_dir = self.install_purelib |
||
252 | self.script_dir = self.install_scripts |
||
253 | # default --record from the install command
|
||
254 | self.set_undefined_options('install', ('record', 'record')) |
||
255 | normpath = map(normalize_path, sys.path)
|
||
256 | self.all_site_dirs = get_site_dirs()
|
||
257 | if self.site_dirs is not None: |
||
258 | site_dirs = [ |
||
259 | os.path.expanduser(s.strip()) for s in self.site_dirs.split(',') |
||
260 | ] |
||
261 | for d in site_dirs: |
||
262 | if not os.path.isdir(d): |
||
263 | log.warn("%s (in --site-dirs) does not exist", d)
|
||
264 | elif normalize_path(d) not in normpath: |
||
265 | raise DistutilsOptionError(
|
||
266 | d+" (in --site-dirs) is not on sys.path"
|
||
267 | ) |
||
268 | else:
|
||
269 | self.all_site_dirs.append(normalize_path(d))
|
||
270 | if not self.editable: self.check_site_dir() |
||
271 | self.index_url = self.index_url or "http://pypi.python.org/simple" |
||
272 | self.shadow_path = self.all_site_dirs[:] |
||
273 | for path_item in self.install_dir, normalize_path(self.script_dir): |
||
274 | if path_item not in self.shadow_path: |
||
275 | self.shadow_path.insert(0, path_item) |
||
276 | |||
277 | if self.allow_hosts is not None: |
||
278 | hosts = [s.strip() for s in self.allow_hosts.split(',')] |
||
279 | else:
|
||
280 | hosts = ['*']
|
||
281 | if self.package_index is None: |
||
282 | self.package_index = self.create_index( |
||
283 | self.index_url, search_path = self.shadow_path, hosts=hosts, |
||
284 | ) |
||
285 | self.local_index = Environment(self.shadow_path+sys.path) |
||
286 | |||
287 | if self.find_links is not None: |
||
288 | if isinstance(self.find_links, basestring): |
||
289 | self.find_links = self.find_links.split() |
||
290 | else:
|
||
291 | self.find_links = []
|
||
292 | if self.local_snapshots_ok: |
||
293 | self.package_index.scan_egg_links(self.shadow_path+sys.path) |
||
294 | if not self.no_find_links: |
||
295 | self.package_index.add_find_links(self.find_links) |
||
296 | self.set_undefined_options('install_lib', ('optimize','optimize')) |
||
297 | if not isinstance(self.optimize,int): |
||
298 | try:
|
||
299 | self.optimize = int(self.optimize) |
||
300 | if not (0 <= self.optimize <= 2): raise ValueError |
||
301 | except ValueError: |
||
302 | raise DistutilsOptionError("--optimize must be 0, 1, or 2") |
||
303 | |||
304 | if self.delete_conflicting and self.ignore_conflicts_at_my_risk: |
||
305 | raise DistutilsOptionError(
|
||
306 | "Can't use both --delete-conflicting and "
|
||
307 | "--ignore-conflicts-at-my-risk at the same time"
|
||
308 | ) |
||
309 | if self.editable and not self.build_directory: |
||
310 | raise DistutilsArgError(
|
||
311 | "Must specify a build directory (-b) when using --editable"
|
||
312 | ) |
||
313 | if not self.args: |
||
314 | raise DistutilsArgError(
|
||
315 | "No urls, filenames, or requirements specified (see --help)")
|
||
316 | |||
317 | self.outputs = []
|
||
318 | |||
319 | |||
320 | def _expand_attrs(self, attrs): |
||
321 | for attr in attrs: |
||
322 | val = getattr(self, attr) |
||
323 | if val is not None: |
||
324 | if os.name == 'posix' or os.name == 'nt': |
||
325 | val = os.path.expanduser(val) |
||
326 | val = subst_vars(val, self.config_vars)
|
||
327 | setattr(self, attr, val) |
||
328 | |||
329 | def expand_basedirs(self): |
||
330 | """Calls `os.path.expanduser` on install_base, install_platbase and
|
||
331 | root."""
|
||
332 | self._expand_attrs(['install_base', 'install_platbase', 'root']) |
||
333 | |||
334 | def expand_dirs(self): |
||
335 | """Calls `os.path.expanduser` on install dirs."""
|
||
336 | self._expand_attrs(['install_purelib', 'install_platlib', |
||
337 | 'install_lib', 'install_headers', |
||
338 | 'install_scripts', 'install_data',]) |
||
339 | |||
340 | def run(self): |
||
341 | if self.verbose != self.distribution.verbose: |
||
342 | log.set_verbosity(self.verbose)
|
||
343 | try:
|
||
344 | for spec in self.args: |
||
345 | self.easy_install(spec, not self.no_deps) |
||
346 | if self.record: |
||
347 | outputs = self.outputs
|
||
348 | if self.root: # strip any package prefix |
||
349 | root_len = len(self.root) |
||
350 | for counter in xrange(len(outputs)): |
||
351 | outputs[counter] = outputs[counter][root_len:] |
||
352 | from distutils import file_util |
||
353 | self.execute(
|
||
354 | file_util.write_file, (self.record, outputs),
|
||
355 | "writing list of installed files to '%s'" %
|
||
356 | self.record
|
||
357 | ) |
||
358 | self.warn_deprecated_options()
|
||
359 | finally:
|
||
360 | log.set_verbosity(self.distribution.verbose)
|
||
361 | |||
362 | def pseudo_tempname(self): |
||
363 | """Return a pseudo-tempname base in the install directory.
|
||
364 | This code is intentionally naive; if a malicious party can write to
|
||
365 | the target directory you're already in deep doodoo.
|
||
366 | """
|
||
367 | try:
|
||
368 | pid = os.getpid() |
||
369 | except:
|
||
370 | pid = random.randint(0,sys.maxint)
|
||
371 | return os.path.join(self.install_dir, "test-easy-install-%s" % pid) |
||
372 | |||
373 | def warn_deprecated_options(self): |
||
374 | if self.delete_conflicting or self.ignore_conflicts_at_my_risk: |
||
375 | log.warn( |
||
376 | "Note: The -D, --delete-conflicting and"
|
||
377 | " --ignore-conflicts-at-my-risk no longer have any purpose"
|
||
378 | " and should not be used."
|
||
379 | ) |
||
380 | |||
381 | def check_site_dir(self): |
||
382 | """Verify that self.install_dir is .pth-capable dir, if needed"""
|
||
383 | |||
384 | instdir = normalize_path(self.install_dir)
|
||
385 | pth_file = os.path.join(instdir,'easy-install.pth')
|
||
386 | |||
387 | # Is it a configured, PYTHONPATH, implicit, or explicit site dir?
|
||
388 | is_site_dir = instdir in self.all_site_dirs |
||
389 | |||
390 | if not is_site_dir: |
||
391 | # No? Then directly test whether it does .pth file processing
|
||
392 | is_site_dir = self.check_pth_processing()
|
||
393 | else:
|
||
394 | # make sure we can write to target dir
|
||
395 | testfile = self.pseudo_tempname()+'.write-test' |
||
396 | test_exists = os.path.exists(testfile) |
||
397 | try:
|
||
398 | if test_exists: os.unlink(testfile)
|
||
399 | open(testfile,'w').close() |
||
400 | os.unlink(testfile) |
||
401 | except (OSError,IOError): |
||
402 | self.cant_write_to_target()
|
||
403 | |||
404 | if not is_site_dir and not self.multi_version: |
||
405 | # Can't install non-multi to non-site dir
|
||
406 | raise DistutilsError(self.no_default_version_msg()) |
||
407 | |||
408 | if is_site_dir:
|
||
409 | if self.pth_file is None: |
||
410 | self.pth_file = PthDistributions(pth_file, self.all_site_dirs) |
||
411 | else:
|
||
412 | self.pth_file = None |
||
413 | |||
414 | PYTHONPATH = os.environ.get('PYTHONPATH','').split(os.pathsep) |
||
415 | if instdir not in map(normalize_path, filter(None,PYTHONPATH)): |
||
416 | # only PYTHONPATH dirs need a site.py, so pretend it's there
|
||
417 | self.sitepy_installed = True |
||
418 | elif self.multi_version and not os.path.exists(pth_file): |
||
419 | self.sitepy_installed = True # don't need site.py in this case |
||
420 | self.pth_file = None # and don't create a .pth file |
||
421 | self.install_dir = instdir
|
||
422 | |||
423 | def cant_write_to_target(self): |
||
424 | msg = """can't create or remove files in install directory
|
||
425 |
|
||
426 | The following error occurred while trying to add or remove files in the
|
||
427 | installation directory:
|
||
428 |
|
||
429 | %s
|
||
430 |
|
||
431 | The installation directory you specified (via --install-dir, --prefix, or
|
||
432 | the distutils default setting) was:
|
||
433 |
|
||
434 | %s
|
||
435 | """ % (sys.exc_info()[1], self.install_dir,) |
||
436 | |||
437 | if not os.path.exists(self.install_dir): |
||
438 | msg += """
|
||
439 | This directory does not currently exist. Please create it and try again, or
|
||
440 | choose a different installation directory (using the -d or --install-dir
|
||
441 | option).
|
||
442 | """
|
||
443 | else:
|
||
444 | msg += """
|
||
445 | Perhaps your account does not have write access to this directory? If the
|
||
446 | installation directory is a system-owned directory, you may need to sign in
|
||
447 | as the administrator or "root" account. If you do not have administrative
|
||
448 | access to this machine, you may wish to choose a different installation
|
||
449 | directory, preferably one that is listed in your PYTHONPATH environment
|
||
450 | variable.
|
||
451 |
|
||
452 | For information on other options, you may wish to consult the
|
||
453 | documentation at:
|
||
454 |
|
||
455 | http://packages.python.org/distribute/easy_install.html
|
||
456 |
|
||
457 | Please make the appropriate changes for your system and try again.
|
||
458 | """
|
||
459 | raise DistutilsError(msg)
|
||
460 | |||
461 | |||
462 | |||
463 | |||
464 | def check_pth_processing(self): |
||
465 | """Empirically verify whether .pth files are supported in inst. dir"""
|
||
466 | instdir = self.install_dir
|
||
467 | log.info("Checking .pth file support in %s", instdir)
|
||
468 | pth_file = self.pseudo_tempname()+".pth" |
||
469 | ok_file = pth_file+'.ok'
|
||
470 | ok_exists = os.path.exists(ok_file) |
||
471 | try:
|
||
472 | if ok_exists: os.unlink(ok_file)
|
||
473 | dirname = os.path.dirname(ok_file) |
||
474 | if not os.path.exists(dirname): |
||
475 | os.makedirs(dirname) |
||
476 | f = open(pth_file,'w') |
||
477 | except (OSError,IOError): |
||
478 | self.cant_write_to_target()
|
||
479 | else:
|
||
480 | try:
|
||
481 | f.write("import os;open(%r,'w').write('OK')\n" % (ok_file,))
|
||
482 | f.close(); f=None
|
||
483 | executable = sys.executable |
||
484 | if os.name=='nt': |
||
485 | dirname,basename = os.path.split(executable) |
||
486 | alt = os.path.join(dirname,'pythonw.exe')
|
||
487 | if basename.lower()=='python.exe' and os.path.exists(alt): |
||
488 | # use pythonw.exe to avoid opening a console window
|
||
489 | executable = alt |
||
490 | |||
491 | from distutils.spawn import spawn |
||
492 | spawn([executable,'-E','-c','pass'],0) |
||
493 | |||
494 | if os.path.exists(ok_file):
|
||
495 | log.info( |
||
496 | "TEST PASSED: %s appears to support .pth files",
|
||
497 | instdir |
||
498 | ) |
||
499 | return True |
||
500 | finally:
|
||
501 | if f: f.close()
|
||
502 | if os.path.exists(ok_file): os.unlink(ok_file)
|
||
503 | if os.path.exists(pth_file): os.unlink(pth_file)
|
||
504 | if not self.multi_version: |
||
505 | log.warn("TEST FAILED: %s does NOT support .pth files", instdir)
|
||
506 | return False |
||
507 | |||
508 | def install_egg_scripts(self, dist): |
||
509 | """Write all the scripts for `dist`, unless scripts are excluded"""
|
||
510 | if not self.exclude_scripts and dist.metadata_isdir('scripts'): |
||
511 | for script_name in dist.metadata_listdir('scripts'): |
||
512 | self.install_script(
|
||
513 | dist, script_name, |
||
514 | dist.get_metadata('scripts/'+script_name)
|
||
515 | ) |
||
516 | self.install_wrapper_scripts(dist)
|
||
517 | |||
518 | def add_output(self, path): |
||
519 | if os.path.isdir(path):
|
||
520 | for base, dirs, files in os.walk(path): |
||
521 | for filename in files: |
||
522 | self.outputs.append(os.path.join(base,filename))
|
||
523 | else:
|
||
524 | self.outputs.append(path)
|
||
525 | |||
526 | def not_editable(self, spec): |
||
527 | if self.editable: |
||
528 | raise DistutilsArgError(
|
||
529 | "Invalid argument %r: you can't use filenames or URLs "
|
||
530 | "with --editable (except via the --find-links option)."
|
||
531 | % (spec,) |
||
532 | ) |
||
533 | |||
534 | def check_editable(self,spec): |
||
535 | if not self.editable: |
||
536 | return
|
||
537 | |||
538 | if os.path.exists(os.path.join(self.build_directory, spec.key)): |
||
539 | raise DistutilsArgError(
|
||
540 | "%r already exists in %s; can't do a checkout there" %
|
||
541 | (spec.key, self.build_directory)
|
||
542 | ) |
||
543 | |||
544 | |||
545 | |||
546 | |||
547 | |||
548 | |||
549 | def easy_install(self, spec, deps=False): |
||
550 | tmpdir = tempfile.mkdtemp(prefix="easy_install-")
|
||
551 | download = None
|
||
552 | if not self.editable: self.install_site_py() |
||
553 | |||
554 | try:
|
||
555 | if not isinstance(spec,Requirement): |
||
556 | if URL_SCHEME(spec):
|
||
557 | # It's a url, download it to tmpdir and process
|
||
558 | self.not_editable(spec)
|
||
559 | download = self.package_index.download(spec, tmpdir)
|
||
560 | return self.install_item(None, download, tmpdir, deps, True) |
||
561 | |||
562 | elif os.path.exists(spec):
|
||
563 | # Existing file or directory, just process it directly
|
||
564 | self.not_editable(spec)
|
||
565 | return self.install_item(None, spec, tmpdir, deps, True) |
||
566 | else:
|
||
567 | spec = parse_requirement_arg(spec) |
||
568 | |||
569 | self.check_editable(spec)
|
||
570 | dist = self.package_index.fetch_distribution(
|
||
571 | spec, tmpdir, self.upgrade, self.editable, not self.always_copy, |
||
572 | self.local_index
|
||
573 | ) |
||
574 | |||
575 | if dist is None: |
||
576 | msg = "Could not find suitable distribution for %r" % spec
|
||
577 | if self.always_copy: |
||
578 | msg+=" (--always-copy skips system and development eggs)"
|
||
579 | raise DistutilsError(msg)
|
||
580 | elif dist.precedence==DEVELOP_DIST:
|
||
581 | # .egg-info dists don't need installing, just process deps
|
||
582 | self.process_distribution(spec, dist, deps, "Using") |
||
583 | return dist
|
||
584 | else:
|
||
585 | return self.install_item(spec, dist.location, tmpdir, deps) |
||
586 | |||
587 | finally:
|
||
588 | if os.path.exists(tmpdir):
|
||
589 | rmtree(tmpdir) |
||
590 | |||
591 | def install_item(self, spec, download, tmpdir, deps, install_needed=False): |
||
592 | |||
593 | # Installation is also needed if file in tmpdir or is not an egg
|
||
594 | install_needed = install_needed or self.always_copy |
||
595 | install_needed = install_needed or os.path.dirname(download) == tmpdir
|
||
596 | install_needed = install_needed or not download.endswith('.egg') |
||
597 | install_needed = install_needed or (
|
||
598 | self.always_copy_from is not None and |
||
599 | os.path.dirname(normalize_path(download)) == |
||
600 | normalize_path(self.always_copy_from)
|
||
601 | ) |
||
602 | |||
603 | if spec and not install_needed: |
||
604 | # at this point, we know it's a local .egg, we just don't know if
|
||
605 | # it's already installed.
|
||
606 | for dist in self.local_index[spec.project_name]: |
||
607 | if dist.location==download:
|
||
608 | break
|
||
609 | else:
|
||
610 | install_needed = True # it's not in the local index |
||
611 | |||
612 | log.info("Processing %s", os.path.basename(download))
|
||
613 | |||
614 | if install_needed:
|
||
615 | dists = self.install_eggs(spec, download, tmpdir)
|
||
616 | for dist in dists: |
||
617 | self.process_distribution(spec, dist, deps)
|
||
618 | else:
|
||
619 | dists = [self.check_conflicts(self.egg_distribution(download))] |
||
620 | self.process_distribution(spec, dists[0], deps, "Using") |
||
621 | |||
622 | if spec is not None: |
||
623 | for dist in dists: |
||
624 | if dist in spec: |
||
625 | return dist
|
||
626 | |||
627 | |||
628 | |||
629 | def select_scheme(self, name): |
||
630 | """Sets the install directories by applying the install schemes."""
|
||
631 | # it's the caller's problem if they supply a bad name!
|
||
632 | scheme = INSTALL_SCHEMES[name] |
||
633 | for key in SCHEME_KEYS: |
||
634 | attrname = 'install_' + key
|
||
635 | if getattr(self, attrname) is None: |
||
636 | setattr(self, attrname, scheme[key]) |
||
637 | |||
638 | |||
639 | |||
640 | |||
641 | def process_distribution(self, requirement, dist, deps=True, *info): |
||
642 | self.update_pth(dist)
|
||
643 | self.package_index.add(dist)
|
||
644 | self.local_index.add(dist)
|
||
645 | if not self.editable: |
||
646 | self.install_egg_scripts(dist)
|
||
647 | self.installed_projects[dist.key] = dist
|
||
648 | log.info(self.installation_report(requirement, dist, *info))
|
||
649 | if (dist.has_metadata('dependency_links.txt') and |
||
650 | not self.no_find_links): |
||
651 | self.package_index.add_find_links(
|
||
652 | dist.get_metadata_lines('dependency_links.txt')
|
||
653 | ) |
||
654 | if not deps and not self.always_copy: |
||
655 | return
|
||
656 | elif requirement is not None and dist.key != requirement.key: |
||
657 | log.warn("Skipping dependencies for %s", dist)
|
||
658 | return # XXX this is not the distribution we were looking for |
||
659 | elif requirement is None or dist not in requirement: |
||
660 | # if we wound up with a different version, resolve what we've got
|
||
661 | distreq = dist.as_requirement() |
||
662 | requirement = requirement or distreq
|
||
663 | requirement = Requirement( |
||
664 | distreq.project_name, distreq.specs, requirement.extras |
||
665 | ) |
||
666 | log.info("Processing dependencies for %s", requirement)
|
||
667 | try:
|
||
668 | distros = WorkingSet([]).resolve( |
||
669 | [requirement], self.local_index, self.easy_install |
||
670 | ) |
||
671 | except DistributionNotFound, e:
|
||
672 | raise DistutilsError(
|
||
673 | "Could not find required distribution %s" % e.args
|
||
674 | ) |
||
675 | except VersionConflict, e:
|
||
676 | raise DistutilsError(
|
||
677 | "Installed distribution %s conflicts with requirement %s"
|
||
678 | % e.args |
||
679 | ) |
||
680 | if self.always_copy or self.always_copy_from: |
||
681 | # Force all the relevant distros to be copied or activated
|
||
682 | for dist in distros: |
||
683 | if dist.key not in self.installed_projects: |
||
684 | self.easy_install(dist.as_requirement())
|
||
685 | log.info("Finished processing dependencies for %s", requirement)
|
||
686 | |||
687 | def should_unzip(self, dist): |
||
688 | if self.zip_ok is not None: |
||
689 | return not self.zip_ok |
||
690 | if dist.has_metadata('not-zip-safe'): |
||
691 | return True |
||
692 | if not dist.has_metadata('zip-safe'): |
||
693 | return True |
||
694 | return True |
||
695 | |||
696 | def maybe_move(self, spec, dist_filename, setup_base): |
||
697 | dst = os.path.join(self.build_directory, spec.key)
|
||
698 | if os.path.exists(dst):
|
||
699 | log.warn( |
||
700 | "%r already exists in %s; build directory %s will not be kept",
|
||
701 | spec.key, self.build_directory, setup_base
|
||
702 | ) |
||
703 | return setup_base
|
||
704 | if os.path.isdir(dist_filename):
|
||
705 | setup_base = dist_filename |
||
706 | else:
|
||
707 | if os.path.dirname(dist_filename)==setup_base:
|
||
708 | os.unlink(dist_filename) # get it out of the tmp dir
|
||
709 | contents = os.listdir(setup_base) |
||
710 | if len(contents)==1: |
||
711 | dist_filename = os.path.join(setup_base,contents[0])
|
||
712 | if os.path.isdir(dist_filename):
|
||
713 | # if the only thing there is a directory, move it instead
|
||
714 | setup_base = dist_filename |
||
715 | ensure_directory(dst); shutil.move(setup_base, dst) |
||
716 | return dst
|
||
717 | |||
718 | def install_wrapper_scripts(self, dist): |
||
719 | if not self.exclude_scripts: |
||
720 | for args in get_script_args(dist): |
||
721 | self.write_script(*args)
|
||
722 | |||
723 | |||
724 | |||
725 | def install_script(self, dist, script_name, script_text, dev_path=None): |
||
726 | """Generate a legacy script wrapper and install it"""
|
||
727 | spec = str(dist.as_requirement())
|
||
728 | is_script = is_python_script(script_text, script_name) |
||
729 | |||
730 | if is_script and dev_path: |
||
731 | script_text = get_script_header(script_text) + ( |
||
732 | "# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r\n"
|
||
733 | "__requires__ = %(spec)r\n"
|
||
734 | "from pkg_resources import require; require(%(spec)r)\n"
|
||
735 | "del require\n"
|
||
736 | "__file__ = %(dev_path)r\n"
|
||
737 | "execfile(__file__)\n"
|
||
738 | ) % locals()
|
||
739 | elif is_script:
|
||
740 | script_text = get_script_header(script_text) + ( |
||
741 | "# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r\n"
|
||
742 | "__requires__ = %(spec)r\n"
|
||
743 | "import pkg_resources\n"
|
||
744 | "pkg_resources.run_script(%(spec)r, %(script_name)r)\n"
|
||
745 | ) % locals()
|
||
746 | self.write_script(script_name, _to_ascii(script_text), 'b') |
||
747 | |||
748 | def write_script(self, script_name, contents, mode="t", blockers=()): |
||
749 | """Write an executable file to the scripts directory"""
|
||
750 | self.delete_blockers( # clean up old .py/.pyw w/o a script |
||
751 | [os.path.join(self.script_dir,x) for x in blockers]) |
||
752 | log.info("Installing %s script to %s", script_name, self.script_dir) |
||
753 | target = os.path.join(self.script_dir, script_name)
|
||
754 | self.add_output(target)
|
||
755 | |||
756 | if not self.dry_run: |
||
757 | ensure_directory(target) |
||
758 | f = open(target,"w"+mode) |
||
759 | f.write(contents) |
||
760 | f.close() |
||
761 | chmod(target,0755)
|
||
762 | |||
763 | |||
764 | |||
765 | |||
766 | def install_eggs(self, spec, dist_filename, tmpdir): |
||
767 | # .egg dirs or files are already built, so just return them
|
||
768 | if dist_filename.lower().endswith('.egg'): |
||
769 | return [self.install_egg(dist_filename, tmpdir)] |
||
770 | elif dist_filename.lower().endswith('.exe'): |
||
771 | return [self.install_exe(dist_filename, tmpdir)] |
||
772 | |||
773 | # Anything else, try to extract and build
|
||
774 | setup_base = tmpdir |
||
775 | if os.path.isfile(dist_filename) and not dist_filename.endswith('.py'): |
||
776 | unpack_archive(dist_filename, tmpdir, self.unpack_progress)
|
||
777 | elif os.path.isdir(dist_filename):
|
||
778 | setup_base = os.path.abspath(dist_filename) |
||
779 | |||
780 | if (setup_base.startswith(tmpdir) # something we downloaded |
||
781 | and self.build_directory and spec is not None |
||
782 | ): |
||
783 | setup_base = self.maybe_move(spec, dist_filename, setup_base)
|
||
784 | |||
785 | # Find the setup.py file
|
||
786 | setup_script = os.path.join(setup_base, 'setup.py')
|
||
787 | |||
788 | if not os.path.exists(setup_script): |
||
789 | setups = glob(os.path.join(setup_base, '*', 'setup.py')) |
||
790 | if not setups: |
||
791 | raise DistutilsError(
|
||
792 | "Couldn't find a setup script in %s" % os.path.abspath(dist_filename)
|
||
793 | ) |
||
794 | if len(setups)>1: |
||
795 | raise DistutilsError(
|
||
796 | "Multiple setup scripts in %s" % os.path.abspath(dist_filename)
|
||
797 | ) |
||
798 | setup_script = setups[0]
|
||
799 | |||
800 | # Now run it, and return the result
|
||
801 | if self.editable: |
||
802 | log.info(self.report_editable(spec, setup_script))
|
||
803 | return []
|
||
804 | else:
|
||
805 | return self.build_and_install(setup_script, setup_base) |
||
806 | |||
807 | def egg_distribution(self, egg_path): |
||
808 | if os.path.isdir(egg_path):
|
||
809 | metadata = PathMetadata(egg_path,os.path.join(egg_path,'EGG-INFO'))
|
||
810 | else:
|
||
811 | metadata = EggMetadata(zipimport.zipimporter(egg_path)) |
||
812 | return Distribution.from_filename(egg_path,metadata=metadata)
|
||
813 | |||
814 | def install_egg(self, egg_path, tmpdir): |
||
815 | destination = os.path.join(self.install_dir,os.path.basename(egg_path))
|
||
816 | destination = os.path.abspath(destination) |
||
817 | if not self.dry_run: |
||
818 | ensure_directory(destination) |
||
819 | |||
820 | dist = self.egg_distribution(egg_path)
|
||
821 | self.check_conflicts(dist)
|
||
822 | if not samefile(egg_path, destination): |
||
823 | if os.path.isdir(destination) and not os.path.islink(destination): |
||
824 | dir_util.remove_tree(destination, dry_run=self.dry_run)
|
||
825 | elif os.path.exists(destination):
|
||
826 | self.execute(os.unlink,(destination,),"Removing "+destination) |
||
827 | uncache_zipdir(destination) |
||
828 | if os.path.isdir(egg_path):
|
||
829 | if egg_path.startswith(tmpdir):
|
||
830 | f,m = shutil.move, "Moving"
|
||
831 | else:
|
||
832 | f,m = shutil.copytree, "Copying"
|
||
833 | elif self.should_unzip(dist): |
||
834 | self.mkpath(destination)
|
||
835 | f,m = self.unpack_and_compile, "Extracting" |
||
836 | elif egg_path.startswith(tmpdir):
|
||
837 | f,m = shutil.move, "Moving"
|
||
838 | else:
|
||
839 | f,m = shutil.copy2, "Copying"
|
||
840 | |||
841 | self.execute(f, (egg_path, destination),
|
||
842 | (m+" %s to %s") %
|
||
843 | (os.path.basename(egg_path),os.path.dirname(destination))) |
||
844 | |||
845 | self.add_output(destination)
|
||
846 | return self.egg_distribution(destination) |
||
847 | |||
848 | def install_exe(self, dist_filename, tmpdir): |
||
849 | # See if it's valid, get data
|
||
850 | cfg = extract_wininst_cfg(dist_filename) |
||
851 | if cfg is None: |
||
852 | raise DistutilsError(
|
||
853 | "%s is not a valid distutils Windows .exe" % dist_filename
|
||
854 | ) |
||
855 | # Create a dummy distribution object until we build the real distro
|
||
856 | dist = Distribution(None,
|
||
857 | project_name=cfg.get('metadata','name'), |
||
858 | version=cfg.get('metadata','version'), platform=get_platform() |
||
859 | ) |
||
860 | |||
861 | # Convert the .exe to an unpacked egg
|
||
862 | egg_path = dist.location = os.path.join(tmpdir, dist.egg_name()+'.egg')
|
||
863 | egg_tmp = egg_path+'.tmp'
|
||
864 | egg_info = os.path.join(egg_tmp, 'EGG-INFO')
|
||
865 | pkg_inf = os.path.join(egg_info, 'PKG-INFO')
|
||
866 | ensure_directory(pkg_inf) # make sure EGG-INFO dir exists
|
||
867 | dist._provider = PathMetadata(egg_tmp, egg_info) # XXX
|
||
868 | self.exe_to_egg(dist_filename, egg_tmp)
|
||
869 | |||
870 | # Write EGG-INFO/PKG-INFO
|
||
871 | if not os.path.exists(pkg_inf): |
||
872 | f = open(pkg_inf,'w') |
||
873 | f.write('Metadata-Version: 1.0\n')
|
||
874 | for k,v in cfg.items('metadata'): |
||
875 | if k<>'target_version': |
||
876 | f.write('%s: %s\n' % (k.replace('_','-').title(), v)) |
||
877 | f.close() |
||
878 | script_dir = os.path.join(egg_info,'scripts')
|
||
879 | self.delete_blockers( # delete entry-point scripts to avoid duping |
||
880 | [os.path.join(script_dir,args[0]) for args in get_script_args(dist)] |
||
881 | ) |
||
882 | # Build .egg file from tmpdir
|
||
883 | bdist_egg.make_zipfile( |
||
884 | egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run |
||
885 | ) |
||
886 | # install the .egg
|
||
887 | return self.install_egg(egg_path, tmpdir) |
||
888 | |||
889 | def exe_to_egg(self, dist_filename, egg_tmp): |
||
890 | """Extract a bdist_wininst to the directories an egg would use"""
|
||
891 | # Check for .pth file and set up prefix translations
|
||
892 | prefixes = get_exe_prefixes(dist_filename) |
||
893 | to_compile = [] |
||
894 | native_libs = [] |
||
895 | top_level = {} |
||
896 | def process(src,dst): |
||
897 | s = src.lower() |
||
898 | for old,new in prefixes: |
||
899 | if s.startswith(old):
|
||
900 | src = new+src[len(old):]
|
||
901 | parts = src.split('/')
|
||
902 | dst = os.path.join(egg_tmp, *parts) |
||
903 | dl = dst.lower() |
||
904 | if dl.endswith('.pyd') or dl.endswith('.dll'): |
||
905 | parts[-1] = bdist_egg.strip_module(parts[-1]) |
||
906 | top_level[os.path.splitext(parts[0])[0]] = 1 |
||
907 | native_libs.append(src) |
||
908 | elif dl.endswith('.py') and old!='SCRIPTS/': |
||
909 | top_level[os.path.splitext(parts[0])[0]] = 1 |
||
910 | to_compile.append(dst) |
||
911 | return dst
|
||
912 | if not src.endswith('.pth'): |
||
913 | log.warn("WARNING: can't process %s", src)
|
||
914 | return None |
||
915 | # extract, tracking .pyd/.dll->native_libs and .py -> to_compile
|
||
916 | unpack_archive(dist_filename, egg_tmp, process) |
||
917 | stubs = [] |
||
918 | for res in native_libs: |
||
919 | if res.lower().endswith('.pyd'): # create stubs for .pyd's |
||
920 | parts = res.split('/')
|
||
921 | resource = parts[-1]
|
||
922 | parts[-1] = bdist_egg.strip_module(parts[-1])+'.py' |
||
923 | pyfile = os.path.join(egg_tmp, *parts) |
||
924 | to_compile.append(pyfile); stubs.append(pyfile) |
||
925 | bdist_egg.write_stub(resource, pyfile) |
||
926 | self.byte_compile(to_compile) # compile .py's |
||
927 | bdist_egg.write_safety_flag(os.path.join(egg_tmp,'EGG-INFO'),
|
||
928 | bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag
|
||
929 | |||
930 | for name in 'top_level','native_libs': |
||
931 | if locals()[name]: |
||
932 | txt = os.path.join(egg_tmp, 'EGG-INFO', name+'.txt') |
||
933 | if not os.path.exists(txt): |
||
934 | f = open(txt,'w') |
||
935 | f.write('\n'.join(locals()[name])+'\n') |
||
936 | f.close() |
||
937 | |||
938 | def check_conflicts(self, dist): |
||
939 | """Verify that there are no conflicting "old-style" packages"""
|
||
940 | |||
941 | return dist # XXX temporarily disable until new strategy is stable |
||
942 | from imp import find_module, get_suffixes |
||
943 | from glob import glob |
||
944 | |||
945 | blockers = [] |
||
946 | names = dict.fromkeys(dist._get_metadata('top_level.txt')) # XXX private attr |
||
947 | |||
948 | exts = {'.pyc':1, '.pyo':1} # get_suffixes() might leave one out |
||
949 | for ext,mode,typ in get_suffixes(): |
||
950 | exts[ext] = 1
|
||
951 | |||
952 | for path,files in expand_paths([self.install_dir]+self.all_site_dirs): |
||
953 | for filename in files: |
||
954 | base,ext = os.path.splitext(filename) |
||
955 | if base in names: |
||
956 | if not ext: |
||
957 | # no extension, check for package
|
||
958 | try:
|
||
959 | f, filename, descr = find_module(base, [path]) |
||
960 | except ImportError: |
||
961 | continue
|
||
962 | else:
|
||
963 | if f: f.close()
|
||
964 | if filename not in blockers: |
||
965 | blockers.append(filename) |
||
966 | elif ext in exts and base!='site': # XXX ugh |
||
967 | blockers.append(os.path.join(path,filename)) |
||
968 | if blockers:
|
||
969 | self.found_conflicts(dist, blockers)
|
||
970 | |||
971 | return dist
|
||
972 | |||
973 | def found_conflicts(self, dist, blockers): |
||
974 | if self.delete_conflicting: |
||
975 | log.warn("Attempting to delete conflicting packages:")
|
||
976 | return self.delete_blockers(blockers) |
||
977 | |||
978 | msg = """\
|
||
979 | -------------------------------------------------------------------------
|
||
980 | CONFLICT WARNING:
|
||
981 |
|
||
982 | The following modules or packages have the same names as modules or
|
||
983 | packages being installed, and will be *before* the installed packages in
|
||
984 | Python's search path. You MUST remove all of the relevant files and
|
||
985 | directories before you will be able to use the package(s) you are
|
||
986 | installing:
|
||
987 |
|
||
988 | %s
|
||
989 |
|
||
990 | """ % '\n '.join(blockers) |
||
991 | |||
992 | if self.ignore_conflicts_at_my_risk: |
||
993 | msg += """\
|
||
994 | (Note: you can run EasyInstall on '%s' with the
|
||
995 | --delete-conflicting option to attempt deletion of the above files
|
||
996 | and/or directories.)
|
||
997 | """ % dist.project_name
|
||
998 | else:
|
||
999 | msg += """\
|
||
1000 | Note: you can attempt this installation again with EasyInstall, and use
|
||
1001 | either the --delete-conflicting (-D) option or the
|
||
1002 | --ignore-conflicts-at-my-risk option, to either delete the above files
|
||
1003 | and directories, or to ignore the conflicts, respectively. Note that if
|
||
1004 | you ignore the conflicts, the installed package(s) may not work.
|
||
1005 | """
|
||
1006 | msg += """\
|
||
1007 | -------------------------------------------------------------------------
|
||
1008 | """
|
||
1009 | sys.stderr.write(msg) |
||
1010 | sys.stderr.flush() |
||
1011 | if not self.ignore_conflicts_at_my_risk: |
||
1012 | raise DistutilsError("Installation aborted due to conflicts") |
||
1013 | |||
1014 | def installation_report(self, req, dist, what="Installed"): |
||
1015 | """Helpful installation message for display to package users"""
|
||
1016 | msg = "\n%(what)s %(eggloc)s%(extras)s"
|
||
1017 | if self.multi_version and not self.no_report: |
||
1018 | msg += """
|
||
1019 |
|
||
1020 | Because this distribution was installed --multi-version, before you can
|
||
1021 | import modules from this package in an application, you will need to
|
||
1022 | 'import pkg_resources' and then use a 'require()' call similar to one of
|
||
1023 | these examples, in order to select the desired version:
|
||
1024 |
|
||
1025 | pkg_resources.require("%(name)s") # latest installed version
|
||
1026 | pkg_resources.require("%(name)s==%(version)s") # this exact version
|
||
1027 | pkg_resources.require("%(name)s>=%(version)s") # this version or higher
|
||
1028 | """
|
||
1029 | if self.install_dir not in map(normalize_path,sys.path): |
||
1030 | msg += """
|
||
1031 |
|
||
1032 | Note also that the installation directory must be on sys.path at runtime for
|
||
1033 | this to work. (e.g. by being the application's script directory, by being on
|
||
1034 | PYTHONPATH, or by being added to sys.path by your code.)
|
||
1035 | """
|
||
1036 | eggloc = dist.location |
||
1037 | name = dist.project_name |
||
1038 | version = dist.version |
||
1039 | extras = '' # TODO: self.report_extras(req, dist) |
||
1040 | return msg % locals() |
||
1041 | |||
1042 | def report_editable(self, spec, setup_script): |
||
1043 | dirname = os.path.dirname(setup_script) |
||
1044 | python = sys.executable |
||
1045 | return """\nExtracted editable version of %(spec)s to %(dirname)s |
||
1046 |
|
||
1047 | If it uses setuptools in its setup script, you can activate it in
|
||
1048 | "development" mode by going to that directory and running::
|
||
1049 |
|
||
1050 | %(python)s setup.py develop
|
||
1051 |
|
||
1052 | See the setuptools documentation for the "develop" command for more info.
|
||
1053 | """ % locals() |
||
1054 | |||
1055 | def run_setup(self, setup_script, setup_base, args): |
||
1056 | sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg)
|
||
1057 | sys.modules.setdefault('distutils.command.egg_info', egg_info)
|
||
1058 | |||
1059 | args = list(args)
|
||
1060 | if self.verbose>2: |
||
1061 | v = 'v' * (self.verbose - 1) |
||
1062 | args.insert(0,'-'+v) |
||
1063 | elif self.verbose<2: |
||
1064 | args.insert(0,'-q') |
||
1065 | if self.dry_run: |
||
1066 | args.insert(0,'-n') |
||
1067 | log.info( |
||
1068 | "Running %s %s", setup_script[len(setup_base)+1:], ' '.join(args) |
||
1069 | ) |
||
1070 | try:
|
||
1071 | run_setup(setup_script, args) |
||
1072 | except SystemExit, v: |
||
1073 | raise DistutilsError("Setup script exited with %s" % (v.args[0],)) |
||
1074 | |||
1075 | def build_and_install(self, setup_script, setup_base): |
||
1076 | args = ['bdist_egg', '--dist-dir'] |
||
1077 | dist_dir = tempfile.mkdtemp( |
||
1078 | prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script)
|
||
1079 | ) |
||
1080 | try:
|
||
1081 | args.append(dist_dir) |
||
1082 | self.run_setup(setup_script, setup_base, args)
|
||
1083 | all_eggs = Environment([dist_dir]) |
||
1084 | eggs = [] |
||
1085 | for key in all_eggs: |
||
1086 | for dist in all_eggs[key]: |
||
1087 | eggs.append(self.install_egg(dist.location, setup_base))
|
||
1088 | if not eggs and not self.dry_run: |
||
1089 | log.warn("No eggs found in %s (setup script problem?)",
|
||
1090 | dist_dir) |
||
1091 | return eggs
|
||
1092 | finally:
|
||
1093 | rmtree(dist_dir) |
||
1094 | log.set_verbosity(self.verbose) # restore our log verbosity |
||
1095 | |||
1096 | def update_pth(self,dist): |
||
1097 | if self.pth_file is None: |
||
1098 | return
|
||
1099 | |||
1100 | for d in self.pth_file[dist.key]: # drop old entries |
||
1101 | if self.multi_version or d.location != dist.location: |
||
1102 | log.info("Removing %s from easy-install.pth file", d)
|
||
1103 | self.pth_file.remove(d)
|
||
1104 | if d.location in self.shadow_path: |
||
1105 | self.shadow_path.remove(d.location)
|
||
1106 | |||
1107 | if not self.multi_version: |
||
1108 | if dist.location in self.pth_file.paths: |
||
1109 | log.info( |
||
1110 | "%s is already the active version in easy-install.pth",
|
||
1111 | dist |
||
1112 | ) |
||
1113 | else:
|
||
1114 | log.info("Adding %s to easy-install.pth file", dist)
|
||
1115 | self.pth_file.add(dist) # add new entry |
||
1116 | if dist.location not in self.shadow_path: |
||
1117 | self.shadow_path.append(dist.location)
|
||
1118 | |||
1119 | if not self.dry_run: |
||
1120 | |||
1121 | self.pth_file.save()
|
||
1122 | if dist.key=='distribute': |
||
1123 | # Ensure that setuptools itself never becomes unavailable!
|
||
1124 | # XXX should this check for latest version?
|
||
1125 | filename = os.path.join(self.install_dir,'setuptools.pth') |
||
1126 | if os.path.islink(filename): os.unlink(filename)
|
||
1127 | f = open(filename, 'wt') |
||
1128 | f.write(self.pth_file.make_relative(dist.location)+'\n') |
||
1129 | f.close() |
||
1130 | |||
1131 | def unpack_progress(self, src, dst): |
||
1132 | # Progress filter for unpacking
|
||
1133 | log.debug("Unpacking %s to %s", src, dst)
|
||
1134 | return dst # only unpack-and-compile skips files for dry run |
||
1135 | |||
1136 | def unpack_and_compile(self, egg_path, destination): |
||
1137 | to_compile = []; to_chmod = [] |
||
1138 | |||
1139 | def pf(src,dst): |
||
1140 | if dst.endswith('.py') and not src.startswith('EGG-INFO/'): |
||
1141 | to_compile.append(dst) |
||
1142 | to_chmod.append(dst) |
||
1143 | elif dst.endswith('.dll') or dst.endswith('.so'): |
||
1144 | to_chmod.append(dst) |
||
1145 | self.unpack_progress(src,dst)
|
||
1146 | return not self.dry_run and dst or None |
||
1147 | |||
1148 | unpack_archive(egg_path, destination, pf) |
||
1149 | self.byte_compile(to_compile)
|
||
1150 | if not self.dry_run: |
||
1151 | for f in to_chmod: |
||
1152 | mode = ((os.stat(f)[stat.ST_MODE]) | 0555) & 07755 |
||
1153 | chmod(f, mode) |
||
1154 | |||
1155 | def byte_compile(self, to_compile): |
||
1156 | if _dont_write_bytecode:
|
||
1157 | self.warn('byte-compiling is disabled, skipping.') |
||
1158 | return
|
||
1159 | |||
1160 | from distutils.util import byte_compile |
||
1161 | try:
|
||
1162 | # try to make the byte compile messages quieter
|
||
1163 | log.set_verbosity(self.verbose - 1) |
||
1164 | |||
1165 | byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run) |
||
1166 | if self.optimize: |
||
1167 | byte_compile( |
||
1168 | to_compile, optimize=self.optimize, force=1, |
||
1169 | dry_run=self.dry_run
|
||
1170 | ) |
||
1171 | finally:
|
||
1172 | log.set_verbosity(self.verbose) # restore original verbosity |
||
1173 | |||
1174 | |||
1175 | |||
1176 | |||
1177 | |||
1178 | |||
1179 | |||
1180 | |||
1181 | def no_default_version_msg(self): |
||
1182 | return """bad install directory or PYTHONPATH |
||
1183 |
|
||
1184 | You are attempting to install a package to a directory that is not
|
||
1185 | on PYTHONPATH and which Python does not read ".pth" files from. The
|
||
1186 | installation directory you specified (via --install-dir, --prefix, or
|
||
1187 | the distutils default setting) was:
|
||
1188 |
|
||
1189 | %s
|
||
1190 |
|
||
1191 | and your PYTHONPATH environment variable currently contains:
|
||
1192 |
|
||
1193 | %r
|
||
1194 |
|
||
1195 | Here are some of your options for correcting the problem:
|
||
1196 |
|
||
1197 | * You can choose a different installation directory, i.e., one that is
|
||
1198 | on PYTHONPATH or supports .pth files
|
||
1199 |
|
||
1200 | * You can add the installation directory to the PYTHONPATH environment
|
||
1201 | variable. (It must then also be on PYTHONPATH whenever you run
|
||
1202 | Python and want to use the package(s) you are installing.)
|
||
1203 |
|
||
1204 | * You can set up the installation directory to support ".pth" files by
|
||
1205 | using one of the approaches described here:
|
||
1206 |
|
||
1207 | http://packages.python.org/distribute/easy_install.html#custom-installation-locations
|
||
1208 |
|
||
1209 | Please make the appropriate changes for your system and try again.""" % (
|
||
1210 | self.install_dir, os.environ.get('PYTHONPATH','') |
||
1211 | ) |
||
1212 | |||
1213 | |||
1214 | |||
1215 | |||
1216 | |||
1217 | |||
1218 | |||
1219 | |||
1220 | |||
1221 | |||
1222 | def install_site_py(self): |
||
1223 | """Make sure there's a site.py in the target dir, if needed"""
|
||
1224 | |||
1225 | if self.sitepy_installed: |
||
1226 | return # already did it, or don't need to |
||
1227 | |||
1228 | sitepy = os.path.join(self.install_dir, "site.py") |
||
1229 | source = resource_string(Requirement.parse("distribute"), "site.py") |
||
1230 | current = ""
|
||
1231 | |||
1232 | if os.path.exists(sitepy):
|
||
1233 | log.debug("Checking existing site.py in %s", self.install_dir) |
||
1234 | f = open(sitepy,'rb') |
||
1235 | current = f.read() |
||
1236 | # we want str, not bytes
|
||
1237 | if sys.version_info >= (3,): |
||
1238 | current = current.decode() |
||
1239 | |||
1240 | f.close() |
||
1241 | if not current.startswith('def __boot():'): |
||
1242 | raise DistutilsError(
|
||
1243 | "%s is not a setuptools-generated site.py; please"
|
||
1244 | " remove it." % sitepy
|
||
1245 | ) |
||
1246 | |||
1247 | if current != source:
|
||
1248 | log.info("Creating %s", sitepy)
|
||
1249 | if not self.dry_run: |
||
1250 | ensure_directory(sitepy) |
||
1251 | f = open(sitepy,'wb') |
||
1252 | f.write(source) |
||
1253 | f.close() |
||
1254 | self.byte_compile([sitepy])
|
||
1255 | |||
1256 | self.sitepy_installed = True |
||
1257 | |||
1258 | |||
1259 | |||
1260 | |||
1261 | def create_home_path(self): |
||
1262 | """Create directories under ~."""
|
||
1263 | if not self.user: |
||
1264 | return
|
||
1265 | home = convert_path(os.path.expanduser("~"))
|
||
1266 | for name, path in self.config_vars.iteritems(): |
||
1267 | if path.startswith(home) and not os.path.isdir(path): |
||
1268 | self.debug_print("os.makedirs('%s', 0700)" % path) |
||
1269 | os.makedirs(path, 0700)
|
||
1270 | |||
1271 | |||
1272 | |||
1273 | |||
1274 | |||
1275 | |||
1276 | |||
1277 | INSTALL_SCHEMES = dict(
|
||
1278 | posix = dict(
|
||
1279 | install_dir = '$base/lib/python$py_version_short/site-packages',
|
||
1280 | script_dir = '$base/bin',
|
||
1281 | ), |
||
1282 | ) |
||
1283 | |||
1284 | DEFAULT_SCHEME = dict(
|
||
1285 | install_dir = '$base/Lib/site-packages',
|
||
1286 | script_dir = '$base/Scripts',
|
||
1287 | ) |
||
1288 | |||
1289 | def _expand(self, *attrs): |
||
1290 | config_vars = self.get_finalized_command('install').config_vars |
||
1291 | |||
1292 | if self.prefix: |
||
1293 | # Set default install_dir/scripts from --prefix
|
||
1294 | config_vars = config_vars.copy() |
||
1295 | config_vars['base'] = self.prefix |
||
1296 | scheme = self.INSTALL_SCHEMES.get(os.name,self.DEFAULT_SCHEME) |
||
1297 | for attr,val in scheme.items(): |
||
1298 | if getattr(self,attr,None) is None: |
||
1299 | setattr(self,attr,val) |
||
1300 | |||
1301 | from distutils.util import subst_vars |
||
1302 | for attr in attrs: |
||
1303 | val = getattr(self, attr) |
||
1304 | if val is not None: |
||
1305 | val = subst_vars(val, config_vars) |
||
1306 | if os.name == 'posix': |
||
1307 | val = os.path.expanduser(val) |
||
1308 | setattr(self, attr, val) |
||
1309 | |||
1310 | |||
1311 | |||
1312 | |||
1313 | |||
1314 | |||
1315 | |||
1316 | |||
1317 | |||
1318 | def get_site_dirs(): |
||
1319 | # return a list of 'site' dirs
|
||
1320 | sitedirs = filter(None,os.environ.get('PYTHONPATH','').split(os.pathsep)) |
||
1321 | prefixes = [sys.prefix] |
||
1322 | if sys.exec_prefix != sys.prefix:
|
||
1323 | prefixes.append(sys.exec_prefix) |
||
1324 | for prefix in prefixes: |
||
1325 | if prefix:
|
||
1326 | if sys.platform in ('os2emx', 'riscos'): |
||
1327 | sitedirs.append(os.path.join(prefix, "Lib", "site-packages")) |
||
1328 | elif os.sep == '/': |
||
1329 | sitedirs.extend([os.path.join(prefix, |
||
1330 | "lib",
|
||
1331 | "python" + sys.version[:3], |
||
1332 | "site-packages"),
|
||
1333 | os.path.join(prefix, "lib", "site-python")]) |
||
1334 | else:
|
||
1335 | sitedirs.extend( |
||
1336 | [prefix, os.path.join(prefix, "lib", "site-packages")] |
||
1337 | ) |
||
1338 | if sys.platform == 'darwin': |
||
1339 | # for framework builds *only* we add the standard Apple
|
||
1340 | # locations. Currently only per-user, but /Library and
|
||
1341 | # /Network/Library could be added too
|
||
1342 | if 'Python.framework' in prefix: |
||
1343 | home = os.environ.get('HOME')
|
||
1344 | if home:
|
||
1345 | sitedirs.append( |
||
1346 | os.path.join(home, |
||
1347 | 'Library',
|
||
1348 | 'Python',
|
||
1349 | sys.version[:3],
|
||
1350 | 'site-packages'))
|
||
1351 | for plat_specific in (0,1): |
||
1352 | site_lib = get_python_lib(plat_specific) |
||
1353 | if site_lib not in sitedirs: sitedirs.append(site_lib) |
||
1354 | |||
1355 | if HAS_USER_SITE:
|
||
1356 | sitedirs.append(site.USER_SITE) |
||
1357 | |||
1358 | sitedirs = map(normalize_path, sitedirs)
|
||
1359 | |||
1360 | return sitedirs
|
||
1361 | |||
1362 | |||
1363 | def expand_paths(inputs): |
||
1364 | """Yield sys.path directories that might contain "old-style" packages"""
|
||
1365 | |||
1366 | seen = {} |
||
1367 | |||
1368 | for dirname in inputs: |
||
1369 | dirname = normalize_path(dirname) |
||
1370 | if dirname in seen: |
||
1371 | continue
|
||
1372 | |||
1373 | seen[dirname] = 1
|
||
1374 | if not os.path.isdir(dirname): |
||
1375 | continue
|
||
1376 | |||
1377 | files = os.listdir(dirname) |
||
1378 | yield dirname, files
|
||
1379 | |||
1380 | for name in files: |
||
1381 | if not name.endswith('.pth'): |
||
1382 | # We only care about the .pth files
|
||
1383 | continue
|
||
1384 | if name in ('easy-install.pth','setuptools.pth'): |
||
1385 | # Ignore .pth files that we control
|
||
1386 | continue
|
||
1387 | |||
1388 | # Read the .pth file
|
||
1389 | f = open(os.path.join(dirname,name))
|
||
1390 | lines = list(yield_lines(f))
|
||
1391 | f.close() |
||
1392 | |||
1393 | # Yield existing non-dupe, non-import directory lines from it
|
||
1394 | for line in lines: |
||
1395 | if not line.startswith("import"): |
||
1396 | line = normalize_path(line.rstrip()) |
||
1397 | if line not in seen: |
||
1398 | seen[line] = 1
|
||
1399 | if not os.path.isdir(line): |
||
1400 | continue
|
||
1401 | yield line, os.listdir(line)
|
||
1402 | |||
1403 | |||
1404 | def extract_wininst_cfg(dist_filename): |
||
1405 | """Extract configuration data from a bdist_wininst .exe
|
||
1406 |
|
||
1407 | Returns a ConfigParser.RawConfigParser, or None
|
||
1408 | """
|
||
1409 | f = open(dist_filename,'rb') |
||
1410 | try:
|
||
1411 | endrec = zipfile._EndRecData(f) |
||
1412 | if endrec is None: |
||
1413 | return None |
||
1414 | |||
1415 | prepended = (endrec[9] - endrec[5]) - endrec[6] |
||
1416 | if prepended < 12: # no wininst data here |
||
1417 | return None |
||
1418 | f.seek(prepended-12)
|
||
1419 | |||
1420 | import struct, StringIO, ConfigParser |
||
1421 | tag, cfglen, bmlen = struct.unpack("<iii",f.read(12)) |
||
1422 | if tag not in (0x1234567A, 0x1234567B): |
||
1423 | return None # not a valid tag |
||
1424 | |||
1425 | f.seek(prepended-(12+cfglen))
|
||
1426 | cfg = ConfigParser.RawConfigParser({'version':'','target_version':''}) |
||
1427 | try:
|
||
1428 | cfg.readfp(StringIO.StringIO(f.read(cfglen).split(chr(0),1)[0])) |
||
1429 | except ConfigParser.Error:
|
||
1430 | return None |
||
1431 | if not cfg.has_section('metadata') or not cfg.has_section('Setup'): |
||
1432 | return None |
||
1433 | return cfg
|
||
1434 | |||
1435 | finally:
|
||
1436 | f.close() |
||
1437 | |||
1438 | |||
1439 | |||
1440 | |||
1441 | |||
1442 | |||
1443 | |||
1444 | |||
1445 | def get_exe_prefixes(exe_filename): |
||
1446 | """Get exe->egg path translations for a given .exe file"""
|
||
1447 | |||
1448 | prefixes = [ |
||
1449 | ('PURELIB/', ''), ('PLATLIB/pywin32_system32', ''), |
||
1450 | ('PLATLIB/', ''), |
||
1451 | ('SCRIPTS/', 'EGG-INFO/scripts/'), |
||
1452 | ('DATA/LIB/site-packages', ''), |
||
1453 | ] |
||
1454 | z = zipfile.ZipFile(exe_filename) |
||
1455 | try:
|
||
1456 | for info in z.infolist(): |
||
1457 | name = info.filename |
||
1458 | parts = name.split('/')
|
||
1459 | if len(parts)==3 and parts[2]=='PKG-INFO': |
||
1460 | if parts[1].endswith('.egg-info'): |
||
1461 | prefixes.insert(0,('/'.join(parts[:2]), 'EGG-INFO/')) |
||
1462 | break
|
||
1463 | if len(parts)<>2 or not name.endswith('.pth'): |
||
1464 | continue
|
||
1465 | if name.endswith('-nspkg.pth'): |
||
1466 | continue
|
||
1467 | if parts[0].upper() in ('PURELIB','PLATLIB'): |
||
1468 | for pth in yield_lines(z.read(name)): |
||
1469 | pth = pth.strip().replace('\\','/') |
||
1470 | if not pth.startswith('import'): |
||
1471 | prefixes.append((('%s/%s/' % (parts[0],pth)), '')) |
||
1472 | finally:
|
||
1473 | z.close() |
||
1474 | prefixes = [(x.lower(),y) for x, y in prefixes] |
||
1475 | prefixes.sort(); prefixes.reverse() |
||
1476 | return prefixes
|
||
1477 | |||
1478 | |||
1479 | def parse_requirement_arg(spec): |
||
1480 | try:
|
||
1481 | return Requirement.parse(spec)
|
||
1482 | except ValueError: |
||
1483 | raise DistutilsError(
|
||
1484 | "Not a URL, existing file, or requirement spec: %r" % (spec,)
|
||
1485 | ) |
||
1486 | |||
1487 | class PthDistributions(Environment): |
||
1488 | """A .pth file with Distribution paths in it"""
|
||
1489 | |||
1490 | dirty = False
|
||
1491 | |||
1492 | def __init__(self, filename, sitedirs=()): |
||
1493 | self.filename = filename; self.sitedirs=map(normalize_path, sitedirs) |
||
1494 | self.basedir = normalize_path(os.path.dirname(self.filename)) |
||
1495 | self._load(); Environment.__init__(self, [], None, None) |
||
1496 | for path in yield_lines(self.paths): |
||
1497 | map(self.add, find_distributions(path, True)) |
||
1498 | |||
1499 | def _load(self): |
||
1500 | self.paths = []
|
||
1501 | saw_import = False
|
||
1502 | seen = dict.fromkeys(self.sitedirs) |
||
1503 | if os.path.isfile(self.filename): |
||
1504 | f = open(self.filename,'rt') |
||
1505 | for line in f: |
||
1506 | if line.startswith('import'): |
||
1507 | saw_import = True
|
||
1508 | continue
|
||
1509 | path = line.rstrip() |
||
1510 | self.paths.append(path)
|
||
1511 | if not path.strip() or path.strip().startswith('#'): |
||
1512 | continue
|
||
1513 | # skip non-existent paths, in case somebody deleted a package
|
||
1514 | # manually, and duplicate paths as well
|
||
1515 | path = self.paths[-1] = normalize_path( |
||
1516 | os.path.join(self.basedir,path)
|
||
1517 | ) |
||
1518 | if not os.path.exists(path) or path in seen: |
||
1519 | self.paths.pop() # skip it |
||
1520 | self.dirty = True # we cleaned up, so we're dirty now :) |
||
1521 | continue
|
||
1522 | seen[path] = 1
|
||
1523 | f.close() |
||
1524 | |||
1525 | if self.paths and not saw_import: |
||
1526 | self.dirty = True # ensure anything we touch has import wrappers |
||
1527 | while self.paths and not self.paths[-1].strip(): |
||
1528 | self.paths.pop()
|
||
1529 | |||
1530 | def save(self): |
||
1531 | """Write changed .pth file back to disk"""
|
||
1532 | if not self.dirty: |
||
1533 | return
|
||
1534 | |||
1535 | data = '\n'.join(map(self.make_relative,self.paths)) |
||
1536 | if data:
|
||
1537 | log.debug("Saving %s", self.filename) |
||
1538 | data = ( |
||
1539 | "import sys; sys.__plen = len(sys.path)\n"
|
||
1540 | "%s\n"
|
||
1541 | "import sys; new=sys.path[sys.__plen:];"
|
||
1542 | " del sys.path[sys.__plen:];"
|
||
1543 | " p=getattr(sys,'__egginsert',0); sys.path[p:p]=new;"
|
||
1544 | " sys.__egginsert = p+len(new)\n"
|
||
1545 | ) % data |
||
1546 | |||
1547 | if os.path.islink(self.filename): |
||
1548 | os.unlink(self.filename)
|
||
1549 | f = open(self.filename,'wt') |
||
1550 | f.write(data); f.close() |
||
1551 | |||
1552 | elif os.path.exists(self.filename): |
||
1553 | log.debug("Deleting empty %s", self.filename) |
||
1554 | os.unlink(self.filename)
|
||
1555 | |||
1556 | self.dirty = False |
||
1557 | |||
1558 | def add(self,dist): |
||
1559 | """Add `dist` to the distribution map"""
|
||
1560 | if (dist.location not in self.paths and ( |
||
1561 | dist.location not in self.sitedirs or |
||
1562 | dist.location == os.getcwd() #account for '.' being in PYTHONPATH
|
||
1563 | )): |
||
1564 | self.paths.append(dist.location)
|
||
1565 | self.dirty = True |
||
1566 | Environment.add(self,dist)
|
||
1567 | |||
1568 | def remove(self,dist): |
||
1569 | """Remove `dist` from the distribution map"""
|
||
1570 | while dist.location in self.paths: |
||
1571 | self.paths.remove(dist.location); self.dirty = True |
||
1572 | Environment.remove(self,dist)
|
||
1573 | |||
1574 | |||
1575 | def make_relative(self,path): |
||
1576 | npath, last = os.path.split(normalize_path(path)) |
||
1577 | baselen = len(self.basedir) |
||
1578 | parts = [last] |
||
1579 | sep = os.altsep=='/' and '/' or os.sep |
||
1580 | while len(npath)>=baselen: |
||
1581 | if npath==self.basedir: |
||
1582 | parts.append(os.curdir) |
||
1583 | parts.reverse() |
||
1584 | return sep.join(parts)
|
||
1585 | npath, last = os.path.split(npath) |
||
1586 | parts.append(last) |
||
1587 | else:
|
||
1588 | return path
|
||
1589 | |||
1590 | def get_script_header(script_text, executable=sys_executable, wininst=False): |
||
1591 | """Create a #! line, getting options (if any) from script_text"""
|
||
1592 | from distutils.command.build_scripts import first_line_re |
||
1593 | |||
1594 | # first_line_re in Python >=3.1.4 and >=3.2.1 is a bytes pattern.
|
||
1595 | if not isinstance(first_line_re.pattern, str): |
||
1596 | first_line_re = re.compile(first_line_re.pattern.decode()) |
||
1597 | |||
1598 | first = (script_text+'\n').splitlines()[0] |
||
1599 | match = first_line_re.match(first) |
||
1600 | options = ''
|
||
1601 | if match:
|
||
1602 | options = match.group(1) or '' |
||
1603 | if options: options = ' '+options |
||
1604 | if wininst:
|
||
1605 | executable = "python.exe"
|
||
1606 | else:
|
||
1607 | executable = nt_quote_arg(executable) |
||
1608 | hdr = "#!%(executable)s%(options)s\n" % locals() |
||
1609 | if not isascii(hdr): |
||
1610 | # Non-ascii path to sys.executable, use -x to prevent warnings
|
||
1611 | if options:
|
||
1612 | if options.strip().startswith('-'): |
||
1613 | options = ' -x'+options.strip()[1:] |
||
1614 | # else: punt, we can't do it, let the warning happen anyway
|
||
1615 | else:
|
||
1616 | options = ' -x'
|
||
1617 | executable = fix_jython_executable(executable, options) |
||
1618 | hdr = "#!%(executable)s%(options)s\n" % locals() |
||
1619 | return hdr
|
||
1620 | |||
1621 | def auto_chmod(func, arg, exc): |
||
1622 | if func is os.remove and os.name=='nt': |
||
1623 | chmod(arg, stat.S_IWRITE) |
||
1624 | return func(arg)
|
||
1625 | exc = sys.exc_info() |
||
1626 | raise exc[0], (exc[1][0], exc[1][1] + (" %s %s" % (func,arg))) |
||
1627 | |||
1628 | def uncache_zipdir(path): |
||
1629 | """Ensure that the importer caches dont have stale info for `path`"""
|
||
1630 | from zipimport import _zip_directory_cache as zdc |
||
1631 | _uncache(path, zdc) |
||
1632 | _uncache(path, sys.path_importer_cache) |
||
1633 | |||
1634 | def _uncache(path, cache): |
||
1635 | if path in cache: |
||
1636 | del cache[path]
|
||
1637 | else:
|
||
1638 | path = normalize_path(path) |
||
1639 | for p in cache: |
||
1640 | if normalize_path(p)==path:
|
||
1641 | del cache[p]
|
||
1642 | return
|
||
1643 | |||
1644 | def is_python(text, filename='<string>'): |
||
1645 | "Is this string a valid Python script?"
|
||
1646 | try:
|
||
1647 | compile(text, filename, 'exec') |
||
1648 | except (SyntaxError, TypeError): |
||
1649 | return False |
||
1650 | else:
|
||
1651 | return True |
||
1652 | |||
1653 | def is_sh(executable): |
||
1654 | """Determine if the specified executable is a .sh (contains a #! line)"""
|
||
1655 | try:
|
||
1656 | fp = open(executable)
|
||
1657 | magic = fp.read(2)
|
||
1658 | fp.close() |
||
1659 | except (OSError,IOError): return executable |
||
1660 | return magic == '#!' |
||
1661 | |||
1662 | def nt_quote_arg(arg): |
||
1663 | """Quote a command line argument according to Windows parsing rules"""
|
||
1664 | |||
1665 | result = [] |
||
1666 | needquote = False
|
||
1667 | nb = 0
|
||
1668 | |||
1669 | needquote = (" " in arg) or ("\t" in arg) |
||
1670 | if needquote:
|
||
1671 | result.append('"')
|
||
1672 | |||
1673 | for c in arg: |
||
1674 | if c == '\\': |
||
1675 | nb += 1
|
||
1676 | elif c == '"': |
||
1677 | # double preceding backslashes, then add a \"
|
||
1678 | result.append('\\' * (nb*2) + '\\"') |
||
1679 | nb = 0
|
||
1680 | else:
|
||
1681 | if nb:
|
||
1682 | result.append('\\' * nb)
|
||
1683 | nb = 0
|
||
1684 | result.append(c) |
||
1685 | |||
1686 | if nb:
|
||
1687 | result.append('\\' * nb)
|
||
1688 | |||
1689 | if needquote:
|
||
1690 | result.append('\\' * nb) # double the trailing backslashes |
||
1691 | result.append('"')
|
||
1692 | |||
1693 | return ''.join(result) |
||
1694 | |||
1695 | |||
1696 | |||
1697 | |||
1698 | |||
1699 | |||
1700 | |||
1701 | |||
1702 | |||
1703 | def is_python_script(script_text, filename): |
||
1704 | """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc.
|
||
1705 | """
|
||
1706 | if filename.endswith('.py') or filename.endswith('.pyw'): |
||
1707 | return True # extension says it's Python |
||
1708 | if is_python(script_text, filename):
|
||
1709 | return True # it's syntactically valid Python |
||
1710 | if script_text.startswith('#!'): |
||
1711 | # It begins with a '#!' line, so check if 'python' is in it somewhere
|
||
1712 | return 'python' in script_text.splitlines()[0].lower() |
||
1713 | |||
1714 | return False # Not any Python I can recognize |
||
1715 | |||
1716 | try:
|
||
1717 | from os import chmod as _chmod |
||
1718 | except ImportError: |
||
1719 | # Jython compatibility
|
||
1720 | def _chmod(*args): pass |
||
1721 | |||
1722 | def chmod(path, mode): |
||
1723 | log.debug("changing mode of %s to %o", path, mode)
|
||
1724 | try:
|
||
1725 | _chmod(path, mode) |
||
1726 | except os.error, e:
|
||
1727 | log.debug("chmod failed: %s", e)
|
||
1728 | |||
1729 | def fix_jython_executable(executable, options): |
||
1730 | if sys.platform.startswith('java') and is_sh(executable): |
||
1731 | # Workaround Jython's sys.executable being a .sh (an invalid
|
||
1732 | # shebang line interpreter)
|
||
1733 | if options:
|
||
1734 | # Can't apply the workaround, leave it broken
|
||
1735 | log.warn("WARNING: Unable to adapt shebang line for Jython,"
|
||
1736 | " the following script is NOT executable\n"
|
||
1737 | " see http://bugs.jython.org/issue1112 for"
|
||
1738 | " more information.")
|
||
1739 | else:
|
||
1740 | return '/usr/bin/env %s' % executable |
||
1741 | return executable
|
||
1742 | |||
1743 | |||
1744 | def get_script_args(dist, executable=sys_executable, wininst=False): |
||
1745 | """Yield write_script() argument tuples for a distribution's entrypoints"""
|
||
1746 | spec = str(dist.as_requirement())
|
||
1747 | header = get_script_header("", executable, wininst)
|
||
1748 | for group in 'console_scripts', 'gui_scripts': |
||
1749 | for name, ep in dist.get_entry_map(group).items(): |
||
1750 | script_text = ( |
||
1751 | "# EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r\n"
|
||
1752 | "__requires__ = %(spec)r\n"
|
||
1753 | "import sys\n"
|
||
1754 | "from pkg_resources import load_entry_point\n"
|
||
1755 | "\n"
|
||
1756 | "if __name__ == '__main__':"
|
||
1757 | "\n"
|
||
1758 | " sys.exit(\n"
|
||
1759 | " load_entry_point(%(spec)r, %(group)r, %(name)r)()\n"
|
||
1760 | " )\n"
|
||
1761 | ) % locals()
|
||
1762 | if sys.platform=='win32' or wininst: |
||
1763 | # On Windows/wininst, add a .py extension and an .exe launcher
|
||
1764 | if group=='gui_scripts': |
||
1765 | ext, launcher = '-script.pyw', 'gui.exe' |
||
1766 | old = ['.pyw']
|
||
1767 | new_header = re.sub('(?i)python.exe','pythonw.exe',header) |
||
1768 | else:
|
||
1769 | ext, launcher = '-script.py', 'cli.exe' |
||
1770 | old = ['.py','.pyc','.pyo'] |
||
1771 | new_header = re.sub('(?i)pythonw.exe','python.exe',header) |
||
1772 | |||
1773 | if os.path.exists(new_header[2:-1]) or sys.platform!='win32': |
||
1774 | hdr = new_header |
||
1775 | else:
|
||
1776 | hdr = header |
||
1777 | yield (name+ext, hdr+script_text, 't', [name+x for x in old]) |
||
1778 | yield (
|
||
1779 | name+'.exe', resource_string('setuptools', launcher), |
||
1780 | 'b' # write in binary mode |
||
1781 | ) |
||
1782 | else:
|
||
1783 | # On other platforms, we assume the right thing to do is to
|
||
1784 | # just write the stub with no extension.
|
||
1785 | yield (name, header+script_text)
|
||
1786 | |||
1787 | def rmtree(path, ignore_errors=False, onerror=auto_chmod): |
||
1788 | """Recursively delete a directory tree.
|
||
1789 |
|
||
1790 | This code is taken from the Python 2.4 version of 'shutil', because
|
||
1791 | the 2.3 version doesn't really work right.
|
||
1792 | """
|
||
1793 | if ignore_errors:
|
||
1794 | def onerror(*args): |
||
1795 | pass
|
||
1796 | elif onerror is None: |
||
1797 | def onerror(*args): |
||
1798 | raise
|
||
1799 | names = [] |
||
1800 | try:
|
||
1801 | names = os.listdir(path) |
||
1802 | except os.error, err:
|
||
1803 | onerror(os.listdir, path, sys.exc_info()) |
||
1804 | for name in names: |
||
1805 | fullname = os.path.join(path, name) |
||
1806 | try:
|
||
1807 | mode = os.lstat(fullname).st_mode |
||
1808 | except os.error:
|
||
1809 | mode = 0
|
||
1810 | if stat.S_ISDIR(mode):
|
||
1811 | rmtree(fullname, ignore_errors, onerror) |
||
1812 | else:
|
||
1813 | try:
|
||
1814 | os.remove(fullname) |
||
1815 | except os.error, err:
|
||
1816 | onerror(os.remove, fullname, sys.exc_info()) |
||
1817 | try:
|
||
1818 | os.rmdir(path) |
||
1819 | except os.error:
|
||
1820 | onerror(os.rmdir, path, sys.exc_info()) |
||
1821 | |||
1822 | def bootstrap(): |
||
1823 | # This function is called when setuptools*.egg is run using /bin/sh
|
||
1824 | import setuptools; argv0 = os.path.dirname(setuptools.__path__[0]) |
||
1825 | sys.argv[0] = argv0; sys.argv.append(argv0); main()
|
||
1826 | |||
1827 | def main(argv=None, **kw): |
||
1828 | from setuptools import setup |
||
1829 | from setuptools.dist import Distribution |
||
1830 | import distutils.core |
||
1831 | |||
1832 | USAGE = """\
|
||
1833 | usage: %(script)s [options] requirement_or_url ...
|
||
1834 | or: %(script)s --help
|
||
1835 | """
|
||
1836 | |||
1837 | def gen_usage (script_name): |
||
1838 | script = os.path.basename(script_name) |
||
1839 | return USAGE % vars() |
||
1840 | |||
1841 | def with_ei_usage(f): |
||
1842 | old_gen_usage = distutils.core.gen_usage |
||
1843 | try:
|
||
1844 | distutils.core.gen_usage = gen_usage |
||
1845 | return f()
|
||
1846 | finally:
|
||
1847 | distutils.core.gen_usage = old_gen_usage |
||
1848 | |||
1849 | class DistributionWithoutHelpCommands(Distribution): |
||
1850 | common_usage = ""
|
||
1851 | |||
1852 | def _show_help(self,*args,**kw): |
||
1853 | with_ei_usage(lambda: Distribution._show_help(self,*args,**kw)) |
||
1854 | |||
1855 | def find_config_files(self): |
||
1856 | files = Distribution.find_config_files(self)
|
||
1857 | if 'setup.cfg' in files: |
||
1858 | files.remove('setup.cfg')
|
||
1859 | return files
|
||
1860 | |||
1861 | if argv is None: |
||
1862 | argv = sys.argv[1:]
|
||
1863 | |||
1864 | with_ei_usage(lambda:
|
||
1865 | setup( |
||
1866 | script_args = ['-q','easy_install', '-v']+argv, |
||
1867 | script_name = sys.argv[0] or 'easy_install', |
||
1868 | distclass=DistributionWithoutHelpCommands, **kw |
||
1869 | ) |
||
1870 | ) |
||
1871 | |||
1872 | |||
1873 |