OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 """Create a "virtual" Python installation | |
3 """ | |
4 | |
5 __version__ = "12.0" | |
6 virtualenv_version = __version__ # legacy | |
7 | |
8 # NB: avoid placing additional imports here, before sys.path is fixed! | |
9 | |
10 import sys | |
11 import os | |
12 | |
13 # | |
14 # RATIONALE: | |
15 # This script is both it's own "host" and "guest". If it's running in "guest | |
16 # mode" (inside the virtualenv interpreter), it's essentially invoked via: | |
17 # /path/to/python /path/to/this/script.py | |
18 # | |
19 # Which, by the nature of Python, will put `/path/to/this` on the system path | |
20 # as the first argument. Now this can cause many subtle bugs, because the | |
21 # rest of the script is now looking to import from the "host" Python version | |
22 # first. This has been especially troublesome when trying to create a Python | |
23 # 3 "guest" env using a Python 2 "host", but even with minor Python | |
24 # differences, there may been some bleeding between environments that doesn't | |
25 # stand out as obviously. | |
26 # | |
27 # This removes the first argument off the system path, to avoid any accidental | |
28 # usage of the "host" library directories. | |
29 # | |
30 if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'): | |
31 del sys.path[0] | |
32 | |
33 import base64 | |
34 import codecs | |
35 import optparse | |
36 import re | |
37 import shutil | |
38 import logging | |
39 import tempfile | |
40 import zlib | |
41 import errno | |
42 import glob | |
43 import distutils.sysconfig | |
44 from distutils.util import strtobool | |
45 import struct | |
46 import subprocess | |
47 import tarfile | |
48 | |
49 if sys.version_info < (2, 6): | |
50 print('ERROR: %s' % sys.exc_info()[1]) | |
51 print('ERROR: this script requires Python 2.6 or greater.') | |
52 sys.exit(101) | |
53 | |
54 try: | |
55 basestring | |
56 except NameError: | |
57 basestring = str | |
58 | |
59 try: | |
60 import ConfigParser | |
61 except ImportError: | |
62 import configparser as ConfigParser | |
63 | |
64 join = os.path.join | |
65 py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1]) | |
66 | |
67 is_jython = sys.platform.startswith('java') | |
68 is_pypy = hasattr(sys, 'pypy_version_info') | |
69 is_win = (sys.platform == 'win32') | |
70 is_cygwin = (sys.platform == 'cygwin') | |
71 is_darwin = (sys.platform == 'darwin') | |
72 abiflags = getattr(sys, 'abiflags', '') | |
73 | |
74 user_dir = os.path.expanduser('~') | |
75 if is_win: | |
76 default_storage_dir = os.path.join(user_dir, 'virtualenv') | |
77 else: | |
78 default_storage_dir = os.path.join(user_dir, '.virtualenv') | |
79 default_config_file = os.path.join(default_storage_dir, 'virtualenv.ini') | |
80 | |
81 if is_pypy: | |
82 expected_exe = 'pypy' | |
83 elif is_jython: | |
84 expected_exe = 'jython' | |
85 else: | |
86 expected_exe = 'python' | |
87 | |
88 # Return a mapping of version -> Python executable | |
89 # Only provided for Windows, where the information in the registry is used | |
90 if not is_win: | |
91 def get_installed_pythons(): | |
92 return {} | |
93 else: | |
94 try: | |
95 import winreg | |
96 except ImportError: | |
97 import _winreg as winreg | |
98 | |
99 def get_installed_pythons(): | |
100 try: | |
101 python_core = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, | |
102 "Software\\Python\\PythonCore") | |
103 except WindowsError: | |
104 # No registered Python installations | |
105 return {} | |
106 i = 0 | |
107 versions = [] | |
108 while True: | |
109 try: | |
110 versions.append(winreg.EnumKey(python_core, i)) | |
111 i = i + 1 | |
112 except WindowsError: | |
113 break | |
114 exes = dict() | |
115 for ver in versions: | |
116 try: | |
117 path = winreg.QueryValue(python_core, "%s\\InstallPath" % ver) | |
118 except WindowsError: | |
119 continue | |
120 exes[ver] = join(path, "python.exe") | |
121 | |
122 winreg.CloseKey(python_core) | |
123 | |
124 # Add the major versions | |
125 # Sort the keys, then repeatedly update the major version entry | |
126 # Last executable (i.e., highest version) wins with this approach | |
127 for ver in sorted(exes): | |
128 exes[ver[0]] = exes[ver] | |
129 | |
130 return exes | |
131 | |
132 REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath', | |
133 'fnmatch', 'locale', 'encodings', 'codecs', | |
134 'stat', 'UserDict', 'readline', 'copy_reg', 'types', | |
135 're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile', | |
136 'zlib'] | |
137 | |
138 REQUIRED_FILES = ['lib-dynload', 'config'] | |
139 | |
140 majver, minver = sys.version_info[:2] | |
141 if majver == 2: | |
142 if minver >= 6: | |
143 REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc']) | |
144 if minver >= 7: | |
145 REQUIRED_MODULES.extend(['_weakrefset']) | |
146 elif majver == 3: | |
147 # Some extra modules are needed for Python 3, but different ones | |
148 # for different versions. | |
149 REQUIRED_MODULES.extend(['_abcoll', 'warnings', 'linecache', 'abc', 'io', | |
150 '_weakrefset', 'copyreg', 'tempfile', 'random', | |
151 '__future__', 'collections', 'keyword', 'tarfile', | |
152 'shutil', 'struct', 'copy', 'tokenize', 'token', | |
153 'functools', 'heapq', 'bisect', 'weakref', | |
154 'reprlib']) | |
155 if minver >= 2: | |
156 REQUIRED_FILES[-1] = 'config-%s' % majver | |
157 if minver >= 3: | |
158 import sysconfig | |
159 platdir = sysconfig.get_config_var('PLATDIR') | |
160 REQUIRED_FILES.append(platdir) | |
161 # The whole list of 3.3 modules is reproduced below - the current | |
162 # uncommented ones are required for 3.3 as of now, but more may be | |
163 # added as 3.3 development continues. | |
164 REQUIRED_MODULES.extend([ | |
165 #"aifc", | |
166 #"antigravity", | |
167 #"argparse", | |
168 #"ast", | |
169 #"asynchat", | |
170 #"asyncore", | |
171 "base64", | |
172 #"bdb", | |
173 #"binhex", | |
174 #"bisect", | |
175 #"calendar", | |
176 #"cgi", | |
177 #"cgitb", | |
178 #"chunk", | |
179 #"cmd", | |
180 #"codeop", | |
181 #"code", | |
182 #"colorsys", | |
183 #"_compat_pickle", | |
184 #"compileall", | |
185 #"concurrent", | |
186 #"configparser", | |
187 #"contextlib", | |
188 #"cProfile", | |
189 #"crypt", | |
190 #"csv", | |
191 #"ctypes", | |
192 #"curses", | |
193 #"datetime", | |
194 #"dbm", | |
195 #"decimal", | |
196 #"difflib", | |
197 #"dis", | |
198 #"doctest", | |
199 #"dummy_threading", | |
200 "_dummy_thread", | |
201 #"email", | |
202 #"filecmp", | |
203 #"fileinput", | |
204 #"formatter", | |
205 #"fractions", | |
206 #"ftplib", | |
207 #"functools", | |
208 #"getopt", | |
209 #"getpass", | |
210 #"gettext", | |
211 #"glob", | |
212 #"gzip", | |
213 "hashlib", | |
214 #"heapq", | |
215 "hmac", | |
216 #"html", | |
217 #"http", | |
218 #"idlelib", | |
219 #"imaplib", | |
220 #"imghdr", | |
221 "imp", | |
222 "importlib", | |
223 #"inspect", | |
224 #"json", | |
225 #"lib2to3", | |
226 #"logging", | |
227 #"macpath", | |
228 #"macurl2path", | |
229 #"mailbox", | |
230 #"mailcap", | |
231 #"_markupbase", | |
232 #"mimetypes", | |
233 #"modulefinder", | |
234 #"multiprocessing", | |
235 #"netrc", | |
236 #"nntplib", | |
237 #"nturl2path", | |
238 #"numbers", | |
239 #"opcode", | |
240 #"optparse", | |
241 #"os2emxpath", | |
242 #"pdb", | |
243 #"pickle", | |
244 #"pickletools", | |
245 #"pipes", | |
246 #"pkgutil", | |
247 #"platform", | |
248 #"plat-linux2", | |
249 #"plistlib", | |
250 #"poplib", | |
251 #"pprint", | |
252 #"profile", | |
253 #"pstats", | |
254 #"pty", | |
255 #"pyclbr", | |
256 #"py_compile", | |
257 #"pydoc_data", | |
258 #"pydoc", | |
259 #"_pyio", | |
260 #"queue", | |
261 #"quopri", | |
262 #"reprlib", | |
263 "rlcompleter", | |
264 #"runpy", | |
265 #"sched", | |
266 #"shelve", | |
267 #"shlex", | |
268 #"smtpd", | |
269 #"smtplib", | |
270 #"sndhdr", | |
271 #"socket", | |
272 #"socketserver", | |
273 #"sqlite3", | |
274 #"ssl", | |
275 #"stringprep", | |
276 #"string", | |
277 #"_strptime", | |
278 #"subprocess", | |
279 #"sunau", | |
280 #"symbol", | |
281 #"symtable", | |
282 #"sysconfig", | |
283 #"tabnanny", | |
284 #"telnetlib", | |
285 #"test", | |
286 #"textwrap", | |
287 #"this", | |
288 #"_threading_local", | |
289 #"threading", | |
290 #"timeit", | |
291 #"tkinter", | |
292 #"tokenize", | |
293 #"token", | |
294 #"traceback", | |
295 #"trace", | |
296 #"tty", | |
297 #"turtledemo", | |
298 #"turtle", | |
299 #"unittest", | |
300 #"urllib", | |
301 #"uuid", | |
302 #"uu", | |
303 #"wave", | |
304 #"weakref", | |
305 #"webbrowser", | |
306 #"wsgiref", | |
307 #"xdrlib", | |
308 #"xml", | |
309 #"xmlrpc", | |
310 #"zipfile", | |
311 ]) | |
312 if minver >= 4: | |
313 REQUIRED_MODULES.extend([ | |
314 'operator', | |
315 '_collections_abc', | |
316 '_bootlocale', | |
317 ]) | |
318 | |
319 if is_pypy: | |
320 # these are needed to correctly display the exceptions that may happen | |
321 # during the bootstrap | |
322 REQUIRED_MODULES.extend(['traceback', 'linecache']) | |
323 | |
324 class Logger(object): | |
325 | |
326 """ | |
327 Logging object for use in command-line script. Allows ranges of | |
328 levels, to avoid some redundancy of displayed information. | |
329 """ | |
330 | |
331 DEBUG = logging.DEBUG | |
332 INFO = logging.INFO | |
333 NOTIFY = (logging.INFO+logging.WARN)/2 | |
334 WARN = WARNING = logging.WARN | |
335 ERROR = logging.ERROR | |
336 FATAL = logging.FATAL | |
337 | |
338 LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL] | |
339 | |
340 def __init__(self, consumers): | |
341 self.consumers = consumers | |
342 self.indent = 0 | |
343 self.in_progress = None | |
344 self.in_progress_hanging = False | |
345 | |
346 def debug(self, msg, *args, **kw): | |
347 self.log(self.DEBUG, msg, *args, **kw) | |
348 def info(self, msg, *args, **kw): | |
349 self.log(self.INFO, msg, *args, **kw) | |
350 def notify(self, msg, *args, **kw): | |
351 self.log(self.NOTIFY, msg, *args, **kw) | |
352 def warn(self, msg, *args, **kw): | |
353 self.log(self.WARN, msg, *args, **kw) | |
354 def error(self, msg, *args, **kw): | |
355 self.log(self.ERROR, msg, *args, **kw) | |
356 def fatal(self, msg, *args, **kw): | |
357 self.log(self.FATAL, msg, *args, **kw) | |
358 def log(self, level, msg, *args, **kw): | |
359 if args: | |
360 if kw: | |
361 raise TypeError( | |
362 "You may give positional or keyword arguments, not both") | |
363 args = args or kw | |
364 rendered = None | |
365 for consumer_level, consumer in self.consumers: | |
366 if self.level_matches(level, consumer_level): | |
367 if (self.in_progress_hanging | |
368 and consumer in (sys.stdout, sys.stderr)): | |
369 self.in_progress_hanging = False | |
370 sys.stdout.write('\n') | |
371 sys.stdout.flush() | |
372 if rendered is None: | |
373 if args: | |
374 rendered = msg % args | |
375 else: | |
376 rendered = msg | |
377 rendered = ' '*self.indent + rendered | |
378 if hasattr(consumer, 'write'): | |
379 consumer.write(rendered+'\n') | |
380 else: | |
381 consumer(rendered) | |
382 | |
383 def start_progress(self, msg): | |
384 assert not self.in_progress, ( | |
385 "Tried to start_progress(%r) while in_progress %r" | |
386 % (msg, self.in_progress)) | |
387 if self.level_matches(self.NOTIFY, self._stdout_level()): | |
388 sys.stdout.write(msg) | |
389 sys.stdout.flush() | |
390 self.in_progress_hanging = True | |
391 else: | |
392 self.in_progress_hanging = False | |
393 self.in_progress = msg | |
394 | |
395 def end_progress(self, msg='done.'): | |
396 assert self.in_progress, ( | |
397 "Tried to end_progress without start_progress") | |
398 if self.stdout_level_matches(self.NOTIFY): | |
399 if not self.in_progress_hanging: | |
400 # Some message has been printed out since start_progress | |
401 sys.stdout.write('...' + self.in_progress + msg + '\n') | |
402 sys.stdout.flush() | |
403 else: | |
404 sys.stdout.write(msg + '\n') | |
405 sys.stdout.flush() | |
406 self.in_progress = None | |
407 self.in_progress_hanging = False | |
408 | |
409 def show_progress(self): | |
410 """If we are in a progress scope, and no log messages have been | |
411 shown, write out another '.'""" | |
412 if self.in_progress_hanging: | |
413 sys.stdout.write('.') | |
414 sys.stdout.flush() | |
415 | |
416 def stdout_level_matches(self, level): | |
417 """Returns true if a message at this level will go to stdout""" | |
418 return self.level_matches(level, self._stdout_level()) | |
419 | |
420 def _stdout_level(self): | |
421 """Returns the level that stdout runs at""" | |
422 for level, consumer in self.consumers: | |
423 if consumer is sys.stdout: | |
424 return level | |
425 return self.FATAL | |
426 | |
427 def level_matches(self, level, consumer_level): | |
428 """ | |
429 >>> l = Logger([]) | |
430 >>> l.level_matches(3, 4) | |
431 False | |
432 >>> l.level_matches(3, 2) | |
433 True | |
434 >>> l.level_matches(slice(None, 3), 3) | |
435 False | |
436 >>> l.level_matches(slice(None, 3), 2) | |
437 True | |
438 >>> l.level_matches(slice(1, 3), 1) | |
439 True | |
440 >>> l.level_matches(slice(2, 3), 1) | |
441 False | |
442 """ | |
443 if isinstance(level, slice): | |
444 start, stop = level.start, level.stop | |
445 if start is not None and start > consumer_level: | |
446 return False | |
447 if stop is not None and stop <= consumer_level: | |
448 return False | |
449 return True | |
450 else: | |
451 return level >= consumer_level | |
452 | |
453 #@classmethod | |
454 def level_for_integer(cls, level): | |
455 levels = cls.LEVELS | |
456 if level < 0: | |
457 return levels[0] | |
458 if level >= len(levels): | |
459 return levels[-1] | |
460 return levels[level] | |
461 | |
462 level_for_integer = classmethod(level_for_integer) | |
463 | |
464 # create a silent logger just to prevent this from being undefined | |
465 # will be overridden with requested verbosity main() is called. | |
466 logger = Logger([(Logger.LEVELS[-1], sys.stdout)]) | |
467 | |
468 def mkdir(path): | |
469 if not os.path.exists(path): | |
470 logger.info('Creating %s', path) | |
471 os.makedirs(path) | |
472 else: | |
473 logger.info('Directory %s already exists', path) | |
474 | |
475 def copyfileordir(src, dest, symlink=True): | |
476 if os.path.isdir(src): | |
477 shutil.copytree(src, dest, symlink) | |
478 else: | |
479 shutil.copy2(src, dest) | |
480 | |
481 def copyfile(src, dest, symlink=True): | |
482 if not os.path.exists(src): | |
483 # Some bad symlink in the src | |
484 logger.warn('Cannot find file %s (bad symlink)', src) | |
485 return | |
486 if os.path.exists(dest): | |
487 logger.debug('File %s already exists', dest) | |
488 return | |
489 if not os.path.exists(os.path.dirname(dest)): | |
490 logger.info('Creating parent directories for %s', os.path.dirname(dest)) | |
491 os.makedirs(os.path.dirname(dest)) | |
492 if not os.path.islink(src): | |
493 srcpath = os.path.abspath(src) | |
494 else: | |
495 srcpath = os.readlink(src) | |
496 if symlink and hasattr(os, 'symlink') and not is_win: | |
497 logger.info('Symlinking %s', dest) | |
498 try: | |
499 os.symlink(srcpath, dest) | |
500 except (OSError, NotImplementedError): | |
501 logger.info('Symlinking failed, copying to %s', dest) | |
502 copyfileordir(src, dest, symlink) | |
503 else: | |
504 logger.info('Copying to %s', dest) | |
505 copyfileordir(src, dest, symlink) | |
506 | |
507 def writefile(dest, content, overwrite=True): | |
508 if not os.path.exists(dest): | |
509 logger.info('Writing %s', dest) | |
510 f = open(dest, 'wb') | |
511 f.write(content.encode('utf-8')) | |
512 f.close() | |
513 return | |
514 else: | |
515 f = open(dest, 'rb') | |
516 c = f.read() | |
517 f.close() | |
518 if c != content.encode("utf-8"): | |
519 if not overwrite: | |
520 logger.notify('File %s exists with different content; not overwr
iting', dest) | |
521 return | |
522 logger.notify('Overwriting %s with new content', dest) | |
523 f = open(dest, 'wb') | |
524 f.write(content.encode('utf-8')) | |
525 f.close() | |
526 else: | |
527 logger.info('Content %s already in place', dest) | |
528 | |
529 def rmtree(dir): | |
530 if os.path.exists(dir): | |
531 logger.notify('Deleting tree %s', dir) | |
532 shutil.rmtree(dir) | |
533 else: | |
534 logger.info('Do not need to delete %s; already gone', dir) | |
535 | |
536 def make_exe(fn): | |
537 if hasattr(os, 'chmod'): | |
538 oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777 | |
539 newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777 | |
540 os.chmod(fn, newmode) | |
541 logger.info('Changed mode of %s to %s', fn, oct(newmode)) | |
542 | |
543 def _find_file(filename, dirs): | |
544 for dir in reversed(dirs): | |
545 files = glob.glob(os.path.join(dir, filename)) | |
546 if files and os.path.isfile(files[0]): | |
547 return True, files[0] | |
548 return False, filename | |
549 | |
550 def file_search_dirs(): | |
551 here = os.path.dirname(os.path.abspath(__file__)) | |
552 dirs = ['.', here, | |
553 join(here, 'virtualenv_support')] | |
554 if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv': | |
555 # Probably some boot script; just in case virtualenv is installed... | |
556 try: | |
557 import virtualenv | |
558 except ImportError: | |
559 pass | |
560 else: | |
561 dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virt
ualenv_support')) | |
562 return [d for d in dirs if os.path.isdir(d)] | |
563 | |
564 | |
565 class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter): | |
566 """ | |
567 Custom help formatter for use in ConfigOptionParser that updates | |
568 the defaults before expanding them, allowing them to show up correctly | |
569 in the help listing | |
570 """ | |
571 def expand_default(self, option): | |
572 if self.parser is not None: | |
573 self.parser.update_defaults(self.parser.defaults) | |
574 return optparse.IndentedHelpFormatter.expand_default(self, option) | |
575 | |
576 | |
577 class ConfigOptionParser(optparse.OptionParser): | |
578 """ | |
579 Custom option parser which updates its defaults by checking the | |
580 configuration files and environmental variables | |
581 """ | |
582 def __init__(self, *args, **kwargs): | |
583 self.config = ConfigParser.RawConfigParser() | |
584 self.files = self.get_config_files() | |
585 self.config.read(self.files) | |
586 optparse.OptionParser.__init__(self, *args, **kwargs) | |
587 | |
588 def get_config_files(self): | |
589 config_file = os.environ.get('VIRTUALENV_CONFIG_FILE', False) | |
590 if config_file and os.path.exists(config_file): | |
591 return [config_file] | |
592 return [default_config_file] | |
593 | |
594 def update_defaults(self, defaults): | |
595 """ | |
596 Updates the given defaults with values from the config files and | |
597 the environ. Does a little special handling for certain types of | |
598 options (lists). | |
599 """ | |
600 # Then go and look for the other sources of configuration: | |
601 config = {} | |
602 # 1. config files | |
603 config.update(dict(self.get_config_section('virtualenv'))) | |
604 # 2. environmental variables | |
605 config.update(dict(self.get_environ_vars())) | |
606 # Then set the options with those values | |
607 for key, val in config.items(): | |
608 key = key.replace('_', '-') | |
609 if not key.startswith('--'): | |
610 key = '--%s' % key # only prefer long opts | |
611 option = self.get_option(key) | |
612 if option is not None: | |
613 # ignore empty values | |
614 if not val: | |
615 continue | |
616 # handle multiline configs | |
617 if option.action == 'append': | |
618 val = val.split() | |
619 else: | |
620 option.nargs = 1 | |
621 if option.action == 'store_false': | |
622 val = not strtobool(val) | |
623 elif option.action in ('store_true', 'count'): | |
624 val = strtobool(val) | |
625 try: | |
626 val = option.convert_value(key, val) | |
627 except optparse.OptionValueError: | |
628 e = sys.exc_info()[1] | |
629 print("An error occurred during configuration: %s" % e) | |
630 sys.exit(3) | |
631 defaults[option.dest] = val | |
632 return defaults | |
633 | |
634 def get_config_section(self, name): | |
635 """ | |
636 Get a section of a configuration | |
637 """ | |
638 if self.config.has_section(name): | |
639 return self.config.items(name) | |
640 return [] | |
641 | |
642 def get_environ_vars(self, prefix='VIRTUALENV_'): | |
643 """ | |
644 Returns a generator with all environmental vars with prefix VIRTUALENV | |
645 """ | |
646 for key, val in os.environ.items(): | |
647 if key.startswith(prefix): | |
648 yield (key.replace(prefix, '').lower(), val) | |
649 | |
650 def get_default_values(self): | |
651 """ | |
652 Overridding to make updating the defaults after instantiation of | |
653 the option parser possible, update_defaults() does the dirty work. | |
654 """ | |
655 if not self.process_default_values: | |
656 # Old, pre-Optik 1.5 behaviour. | |
657 return optparse.Values(self.defaults) | |
658 | |
659 defaults = self.update_defaults(self.defaults.copy()) # ours | |
660 for option in self._get_all_options(): | |
661 default = defaults.get(option.dest) | |
662 if isinstance(default, basestring): | |
663 opt_str = option.get_opt_string() | |
664 defaults[option.dest] = option.check_value(opt_str, default) | |
665 return optparse.Values(defaults) | |
666 | |
667 | |
668 def main(): | |
669 parser = ConfigOptionParser( | |
670 version=virtualenv_version, | |
671 usage="%prog [OPTIONS] DEST_DIR", | |
672 formatter=UpdatingDefaultsHelpFormatter()) | |
673 | |
674 parser.add_option( | |
675 '-v', '--verbose', | |
676 action='count', | |
677 dest='verbose', | |
678 default=0, | |
679 help="Increase verbosity.") | |
680 | |
681 parser.add_option( | |
682 '-q', '--quiet', | |
683 action='count', | |
684 dest='quiet', | |
685 default=0, | |
686 help='Decrease verbosity.') | |
687 | |
688 parser.add_option( | |
689 '-p', '--python', | |
690 dest='python', | |
691 metavar='PYTHON_EXE', | |
692 help='The Python interpreter to use, e.g., --python=python2.5 will use t
he python2.5 ' | |
693 'interpreter to create the new environment. The default is the interpre
ter that ' | |
694 'virtualenv was installed with (%s)' % sys.executable) | |
695 | |
696 parser.add_option( | |
697 '--clear', | |
698 dest='clear', | |
699 action='store_true', | |
700 help="Clear out the non-root install and start from scratch.") | |
701 | |
702 parser.set_defaults(system_site_packages=False) | |
703 parser.add_option( | |
704 '--no-site-packages', | |
705 dest='system_site_packages', | |
706 action='store_false', | |
707 help="DEPRECATED. Retained only for backward compatibility. " | |
708 "Not having access to global site-packages is now the default behav
ior.") | |
709 | |
710 parser.add_option( | |
711 '--system-site-packages', | |
712 dest='system_site_packages', | |
713 action='store_true', | |
714 help="Give the virtual environment access to the global site-packages.") | |
715 | |
716 parser.add_option( | |
717 '--always-copy', | |
718 dest='symlink', | |
719 action='store_false', | |
720 default=True, | |
721 help="Always copy files rather than symlinking.") | |
722 | |
723 parser.add_option( | |
724 '--unzip-setuptools', | |
725 dest='unzip_setuptools', | |
726 action='store_true', | |
727 help="Unzip Setuptools when installing it.") | |
728 | |
729 parser.add_option( | |
730 '--relocatable', | |
731 dest='relocatable', | |
732 action='store_true', | |
733 help='Make an EXISTING virtualenv environment relocatable. ' | |
734 'This fixes up scripts and makes all .pth files relative.') | |
735 | |
736 parser.add_option( | |
737 '--no-setuptools', | |
738 dest='no_setuptools', | |
739 action='store_true', | |
740 help='Do not install setuptools (or pip) in the new virtualenv.') | |
741 | |
742 parser.add_option( | |
743 '--no-pip', | |
744 dest='no_pip', | |
745 action='store_true', | |
746 help='Do not install pip in the new virtualenv.') | |
747 | |
748 default_search_dirs = file_search_dirs() | |
749 parser.add_option( | |
750 '--extra-search-dir', | |
751 dest="search_dirs", | |
752 action="append", | |
753 metavar='DIR', | |
754 default=default_search_dirs, | |
755 help="Directory to look for setuptools/pip distributions in. " | |
756 "This option can be used multiple times.") | |
757 | |
758 parser.add_option( | |
759 '--never-download', | |
760 dest="never_download", | |
761 action="store_true", | |
762 default=True, | |
763 help="DEPRECATED. Retained only for backward compatibility. This option
has no effect. " | |
764 "Virtualenv never downloads pip or setuptools.") | |
765 | |
766 parser.add_option( | |
767 '--prompt', | |
768 dest='prompt', | |
769 help='Provides an alternative prompt prefix for this environment.') | |
770 | |
771 parser.add_option( | |
772 '--setuptools', | |
773 dest='setuptools', | |
774 action='store_true', | |
775 help="DEPRECATED. Retained only for backward compatibility. This option
has no effect.") | |
776 | |
777 parser.add_option( | |
778 '--distribute', | |
779 dest='distribute', | |
780 action='store_true', | |
781 help="DEPRECATED. Retained only for backward compatibility. This option
has no effect.") | |
782 | |
783 if 'extend_parser' in globals(): | |
784 extend_parser(parser) | |
785 | |
786 options, args = parser.parse_args() | |
787 | |
788 global logger | |
789 | |
790 if 'adjust_options' in globals(): | |
791 adjust_options(options, args) | |
792 | |
793 verbosity = options.verbose - options.quiet | |
794 logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)]) | |
795 | |
796 if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'): | |
797 env = os.environ.copy() | |
798 interpreter = resolve_interpreter(options.python) | |
799 if interpreter == sys.executable: | |
800 logger.warn('Already using interpreter %s' % interpreter) | |
801 else: | |
802 logger.notify('Running virtualenv with interpreter %s' % interpreter
) | |
803 env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true' | |
804 file = __file__ | |
805 if file.endswith('.pyc'): | |
806 file = file[:-1] | |
807 popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env
) | |
808 raise SystemExit(popen.wait()) | |
809 | |
810 if not args: | |
811 print('You must provide a DEST_DIR') | |
812 parser.print_help() | |
813 sys.exit(2) | |
814 if len(args) > 1: | |
815 print('There must be only one argument: DEST_DIR (you gave %s)' % ( | |
816 ' '.join(args))) | |
817 parser.print_help() | |
818 sys.exit(2) | |
819 | |
820 home_dir = args[0] | |
821 | |
822 if os.environ.get('WORKING_ENV'): | |
823 logger.fatal('ERROR: you cannot run virtualenv while in a workingenv') | |
824 logger.fatal('Please deactivate your workingenv, then re-run this script
') | |
825 sys.exit(3) | |
826 | |
827 if 'PYTHONHOME' in os.environ: | |
828 logger.warn('PYTHONHOME is set. You *must* activate the virtualenv befo
re using it') | |
829 del os.environ['PYTHONHOME'] | |
830 | |
831 if options.relocatable: | |
832 make_environment_relocatable(home_dir) | |
833 return | |
834 | |
835 if not options.never_download: | |
836 logger.warn('The --never-download option is for backward compatibility o
nly.') | |
837 logger.warn('Setting it to false is no longer supported, and will be ign
ored.') | |
838 | |
839 create_environment(home_dir, | |
840 site_packages=options.system_site_packages, | |
841 clear=options.clear, | |
842 unzip_setuptools=options.unzip_setuptools, | |
843 prompt=options.prompt, | |
844 search_dirs=options.search_dirs, | |
845 never_download=True, | |
846 no_setuptools=options.no_setuptools, | |
847 no_pip=options.no_pip, | |
848 symlink=options.symlink) | |
849 if 'after_install' in globals(): | |
850 after_install(options, home_dir) | |
851 | |
852 def call_subprocess(cmd, show_stdout=True, | |
853 filter_stdout=None, cwd=None, | |
854 raise_on_returncode=True, extra_env=None, | |
855 remove_from_env=None): | |
856 cmd_parts = [] | |
857 for part in cmd: | |
858 if len(part) > 45: | |
859 part = part[:20]+"..."+part[-20:] | |
860 if ' ' in part or '\n' in part or '"' in part or "'" in part: | |
861 part = '"%s"' % part.replace('"', '\\"') | |
862 if hasattr(part, 'decode'): | |
863 try: | |
864 part = part.decode(sys.getdefaultencoding()) | |
865 except UnicodeDecodeError: | |
866 part = part.decode(sys.getfilesystemencoding()) | |
867 cmd_parts.append(part) | |
868 cmd_desc = ' '.join(cmd_parts) | |
869 if show_stdout: | |
870 stdout = None | |
871 else: | |
872 stdout = subprocess.PIPE | |
873 logger.debug("Running command %s" % cmd_desc) | |
874 if extra_env or remove_from_env: | |
875 env = os.environ.copy() | |
876 if extra_env: | |
877 env.update(extra_env) | |
878 if remove_from_env: | |
879 for varname in remove_from_env: | |
880 env.pop(varname, None) | |
881 else: | |
882 env = None | |
883 try: | |
884 proc = subprocess.Popen( | |
885 cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout, | |
886 cwd=cwd, env=env) | |
887 except Exception: | |
888 e = sys.exc_info()[1] | |
889 logger.fatal( | |
890 "Error %s while executing command %s" % (e, cmd_desc)) | |
891 raise | |
892 all_output = [] | |
893 if stdout is not None: | |
894 stdout = proc.stdout | |
895 encoding = sys.getdefaultencoding() | |
896 fs_encoding = sys.getfilesystemencoding() | |
897 while 1: | |
898 line = stdout.readline() | |
899 try: | |
900 line = line.decode(encoding) | |
901 except UnicodeDecodeError: | |
902 line = line.decode(fs_encoding) | |
903 if not line: | |
904 break | |
905 line = line.rstrip() | |
906 all_output.append(line) | |
907 if filter_stdout: | |
908 level = filter_stdout(line) | |
909 if isinstance(level, tuple): | |
910 level, line = level | |
911 logger.log(level, line) | |
912 if not logger.stdout_level_matches(level): | |
913 logger.show_progress() | |
914 else: | |
915 logger.info(line) | |
916 else: | |
917 proc.communicate() | |
918 proc.wait() | |
919 if proc.returncode: | |
920 if raise_on_returncode: | |
921 if all_output: | |
922 logger.notify('Complete output from command %s:' % cmd_desc) | |
923 logger.notify('\n'.join(all_output) + '\n-----------------------
-----------------') | |
924 raise OSError( | |
925 "Command %s failed with error code %s" | |
926 % (cmd_desc, proc.returncode)) | |
927 else: | |
928 logger.warn( | |
929 "Command %s had error code %s" | |
930 % (cmd_desc, proc.returncode)) | |
931 | |
932 def filter_install_output(line): | |
933 if line.strip().startswith('running'): | |
934 return Logger.INFO | |
935 return Logger.DEBUG | |
936 | |
937 def find_wheels(projects, search_dirs): | |
938 """Find wheels from which we can import PROJECTS. | |
939 | |
940 Scan through SEARCH_DIRS for a wheel for each PROJECT in turn. Return | |
941 a list of the first wheel found for each PROJECT | |
942 """ | |
943 | |
944 wheels = [] | |
945 | |
946 # Look through SEARCH_DIRS for the first suitable wheel. Don't bother | |
947 # about version checking here, as this is simply to get something we can | |
948 # then use to install the correct version. | |
949 for project in projects: | |
950 for dirname in search_dirs: | |
951 # This relies on only having "universal" wheels available. | |
952 # The pattern could be tightened to require -py2.py3-none-any.whl. | |
953 files = glob.glob(os.path.join(dirname, project + '-*.whl')) | |
954 if files: | |
955 wheels.append(os.path.abspath(files[0])) | |
956 break | |
957 else: | |
958 # We're out of luck, so quit with a suitable error | |
959 logger.fatal('Cannot find a wheel for %s' % (project,)) | |
960 | |
961 return wheels | |
962 | |
963 def install_wheel(project_names, py_executable, search_dirs=None): | |
964 if search_dirs is None: | |
965 search_dirs = file_search_dirs() | |
966 | |
967 wheels = find_wheels(['setuptools', 'pip'], search_dirs) | |
968 pythonpath = os.pathsep.join(wheels) | |
969 findlinks = ' '.join(search_dirs) | |
970 | |
971 cmd = [ | |
972 py_executable, '-c', | |
973 'import sys, pip; sys.exit(pip.main(["install", "--ignore-installed"] +
sys.argv[1:]))', | |
974 ] + project_names | |
975 logger.start_progress('Installing %s...' % (', '.join(project_names))) | |
976 logger.indent += 2 | |
977 try: | |
978 call_subprocess(cmd, show_stdout=False, | |
979 extra_env = { | |
980 'PYTHONPATH': pythonpath, | |
981 'PIP_FIND_LINKS': findlinks, | |
982 'PIP_USE_WHEEL': '1', | |
983 'PIP_PRE': '1', | |
984 'PIP_NO_INDEX': '1' | |
985 } | |
986 ) | |
987 finally: | |
988 logger.indent -= 2 | |
989 logger.end_progress() | |
990 | |
991 def create_environment(home_dir, site_packages=False, clear=False, | |
992 unzip_setuptools=False, | |
993 prompt=None, search_dirs=None, never_download=False, | |
994 no_setuptools=False, no_pip=False, symlink=True): | |
995 """ | |
996 Creates a new environment in ``home_dir``. | |
997 | |
998 If ``site_packages`` is true, then the global ``site-packages/`` | |
999 directory will be on the path. | |
1000 | |
1001 If ``clear`` is true (default False) then the environment will | |
1002 first be cleared. | |
1003 """ | |
1004 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) | |
1005 | |
1006 py_executable = os.path.abspath(install_python( | |
1007 home_dir, lib_dir, inc_dir, bin_dir, | |
1008 site_packages=site_packages, clear=clear, symlink=symlink)) | |
1009 | |
1010 install_distutils(home_dir) | |
1011 | |
1012 if not no_setuptools: | |
1013 to_install = ['setuptools'] | |
1014 if not no_pip: | |
1015 to_install.append('pip') | |
1016 install_wheel(to_install, py_executable, search_dirs) | |
1017 | |
1018 install_activate(home_dir, bin_dir, prompt) | |
1019 | |
1020 def is_executable_file(fpath): | |
1021 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) | |
1022 | |
1023 def path_locations(home_dir): | |
1024 """Return the path locations for the environment (where libraries are, | |
1025 where scripts go, etc)""" | |
1026 # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its | |
1027 # prefix arg is broken: http://bugs.python.org/issue3386 | |
1028 if is_win: | |
1029 # Windows has lots of problems with executables with spaces in | |
1030 # the name; this function will remove them (using the ~1 | |
1031 # format): | |
1032 mkdir(home_dir) | |
1033 if ' ' in home_dir: | |
1034 import ctypes | |
1035 GetShortPathName = ctypes.windll.kernel32.GetShortPathNameW | |
1036 size = max(len(home_dir)+1, 256) | |
1037 buf = ctypes.create_unicode_buffer(size) | |
1038 try: | |
1039 u = unicode | |
1040 except NameError: | |
1041 u = str | |
1042 ret = GetShortPathName(u(home_dir), buf, size) | |
1043 if not ret: | |
1044 print('Error: the path "%s" has a space in it' % home_dir) | |
1045 print('We could not determine the short pathname for it.') | |
1046 print('Exiting.') | |
1047 sys.exit(3) | |
1048 home_dir = str(buf.value) | |
1049 lib_dir = join(home_dir, 'Lib') | |
1050 inc_dir = join(home_dir, 'Include') | |
1051 bin_dir = join(home_dir, 'Scripts') | |
1052 if is_jython: | |
1053 lib_dir = join(home_dir, 'Lib') | |
1054 inc_dir = join(home_dir, 'Include') | |
1055 bin_dir = join(home_dir, 'bin') | |
1056 elif is_pypy: | |
1057 lib_dir = home_dir | |
1058 inc_dir = join(home_dir, 'include') | |
1059 bin_dir = join(home_dir, 'bin') | |
1060 elif not is_win: | |
1061 lib_dir = join(home_dir, 'lib', py_version) | |
1062 multiarch_exec = '/usr/bin/multiarch-platform' | |
1063 if is_executable_file(multiarch_exec): | |
1064 # In Mageia (2) and Mandriva distros the include dir must be like: | |
1065 # virtualenv/include/multiarch-x86_64-linux/python2.7 | |
1066 # instead of being virtualenv/include/python2.7 | |
1067 p = subprocess.Popen(multiarch_exec, stdout=subprocess.PIPE, stderr=
subprocess.PIPE) | |
1068 stdout, stderr = p.communicate() | |
1069 # stdout.strip is needed to remove newline character | |
1070 inc_dir = join(home_dir, 'include', stdout.strip(), py_version + abi
flags) | |
1071 else: | |
1072 inc_dir = join(home_dir, 'include', py_version + abiflags) | |
1073 bin_dir = join(home_dir, 'bin') | |
1074 return home_dir, lib_dir, inc_dir, bin_dir | |
1075 | |
1076 | |
1077 def change_prefix(filename, dst_prefix): | |
1078 prefixes = [sys.prefix] | |
1079 | |
1080 if is_darwin: | |
1081 prefixes.extend(( | |
1082 os.path.join("/Library/Python", sys.version[:3], "site-packages"), | |
1083 os.path.join(sys.prefix, "Extras", "lib", "python"), | |
1084 os.path.join("~", "Library", "Python", sys.version[:3], "site-packag
es"), | |
1085 # Python 2.6 no-frameworks | |
1086 os.path.join("~", ".local", "lib","python", sys.version[:3], "site-p
ackages"), | |
1087 # System Python 2.7 on OSX Mountain Lion | |
1088 os.path.join("~", "Library", "Python", sys.version[:3], "lib", "pyth
on", "site-packages"))) | |
1089 | |
1090 if hasattr(sys, 'real_prefix'): | |
1091 prefixes.append(sys.real_prefix) | |
1092 if hasattr(sys, 'base_prefix'): | |
1093 prefixes.append(sys.base_prefix) | |
1094 prefixes = list(map(os.path.expanduser, prefixes)) | |
1095 prefixes = list(map(os.path.abspath, prefixes)) | |
1096 # Check longer prefixes first so we don't split in the middle of a filename | |
1097 prefixes = sorted(prefixes, key=len, reverse=True) | |
1098 filename = os.path.abspath(filename) | |
1099 for src_prefix in prefixes: | |
1100 if filename.startswith(src_prefix): | |
1101 _, relpath = filename.split(src_prefix, 1) | |
1102 if src_prefix != os.sep: # sys.prefix == "/" | |
1103 assert relpath[0] == os.sep | |
1104 relpath = relpath[1:] | |
1105 return join(dst_prefix, relpath) | |
1106 assert False, "Filename %s does not start with any of these prefixes: %s" %
\ | |
1107 (filename, prefixes) | |
1108 | |
1109 def copy_required_modules(dst_prefix, symlink): | |
1110 import imp | |
1111 for modname in REQUIRED_MODULES: | |
1112 if modname in sys.builtin_module_names: | |
1113 logger.info("Ignoring built-in bootstrap module: %s" % modname) | |
1114 continue | |
1115 try: | |
1116 f, filename, _ = imp.find_module(modname) | |
1117 except ImportError: | |
1118 logger.info("Cannot import bootstrap module: %s" % modname) | |
1119 else: | |
1120 if f is not None: | |
1121 f.close() | |
1122 # special-case custom readline.so on OS X, but not for pypy: | |
1123 if modname == 'readline' and sys.platform == 'darwin' and not ( | |
1124 is_pypy or filename.endswith(join('lib-dynload', 'readline.s
o'))): | |
1125 dst_filename = join(dst_prefix, 'lib', 'python%s' % sys.version[
:3], 'readline.so') | |
1126 elif modname == 'readline' and sys.platform == 'win32': | |
1127 # special-case for Windows, where readline is not a | |
1128 # standard module, though it may have been installed in | |
1129 # site-packages by a third-party package | |
1130 pass | |
1131 else: | |
1132 dst_filename = change_prefix(filename, dst_prefix) | |
1133 copyfile(filename, dst_filename, symlink) | |
1134 if filename.endswith('.pyc'): | |
1135 pyfile = filename[:-1] | |
1136 if os.path.exists(pyfile): | |
1137 copyfile(pyfile, dst_filename[:-1], symlink) | |
1138 | |
1139 | |
1140 def subst_path(prefix_path, prefix, home_dir): | |
1141 prefix_path = os.path.normpath(prefix_path) | |
1142 prefix = os.path.normpath(prefix) | |
1143 home_dir = os.path.normpath(home_dir) | |
1144 if not prefix_path.startswith(prefix): | |
1145 logger.warn('Path not in prefix %r %r', prefix_path, prefix) | |
1146 return | |
1147 return prefix_path.replace(prefix, home_dir, 1) | |
1148 | |
1149 | |
1150 def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy
mlink=True): | |
1151 """Install just the base environment, no distutils patches etc""" | |
1152 if sys.executable.startswith(bin_dir): | |
1153 print('Please use the *system* python to run this script') | |
1154 return | |
1155 | |
1156 if clear: | |
1157 rmtree(lib_dir) | |
1158 ## FIXME: why not delete it? | |
1159 ## Maybe it should delete everything with #!/path/to/venv/python in it | |
1160 logger.notify('Not deleting %s', bin_dir) | |
1161 | |
1162 if hasattr(sys, 'real_prefix'): | |
1163 logger.notify('Using real prefix %r' % sys.real_prefix) | |
1164 prefix = sys.real_prefix | |
1165 elif hasattr(sys, 'base_prefix'): | |
1166 logger.notify('Using base prefix %r' % sys.base_prefix) | |
1167 prefix = sys.base_prefix | |
1168 else: | |
1169 prefix = sys.prefix | |
1170 mkdir(lib_dir) | |
1171 fix_lib64(lib_dir, symlink) | |
1172 stdlib_dirs = [os.path.dirname(os.__file__)] | |
1173 if is_win: | |
1174 stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs')) | |
1175 elif is_darwin: | |
1176 stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages')) | |
1177 if hasattr(os, 'symlink'): | |
1178 logger.info('Symlinking Python bootstrap modules') | |
1179 else: | |
1180 logger.info('Copying Python bootstrap modules') | |
1181 logger.indent += 2 | |
1182 try: | |
1183 # copy required files... | |
1184 for stdlib_dir in stdlib_dirs: | |
1185 if not os.path.isdir(stdlib_dir): | |
1186 continue | |
1187 for fn in os.listdir(stdlib_dir): | |
1188 bn = os.path.splitext(fn)[0] | |
1189 if fn != 'site-packages' and bn in REQUIRED_FILES: | |
1190 copyfile(join(stdlib_dir, fn), join(lib_dir, fn), symlink) | |
1191 # ...and modules | |
1192 copy_required_modules(home_dir, symlink) | |
1193 finally: | |
1194 logger.indent -= 2 | |
1195 mkdir(join(lib_dir, 'site-packages')) | |
1196 import site | |
1197 site_filename = site.__file__ | |
1198 if site_filename.endswith('.pyc'): | |
1199 site_filename = site_filename[:-1] | |
1200 elif site_filename.endswith('$py.class'): | |
1201 site_filename = site_filename.replace('$py.class', '.py') | |
1202 site_filename_dst = change_prefix(site_filename, home_dir) | |
1203 site_dir = os.path.dirname(site_filename_dst) | |
1204 writefile(site_filename_dst, SITE_PY) | |
1205 writefile(join(site_dir, 'orig-prefix.txt'), prefix) | |
1206 site_packages_filename = join(site_dir, 'no-global-site-packages.txt') | |
1207 if not site_packages: | |
1208 writefile(site_packages_filename, '') | |
1209 | |
1210 if is_pypy or is_win: | |
1211 stdinc_dir = join(prefix, 'include') | |
1212 else: | |
1213 stdinc_dir = join(prefix, 'include', py_version + abiflags) | |
1214 if os.path.exists(stdinc_dir): | |
1215 copyfile(stdinc_dir, inc_dir, symlink) | |
1216 else: | |
1217 logger.debug('No include dir %s' % stdinc_dir) | |
1218 | |
1219 platinc_dir = distutils.sysconfig.get_python_inc(plat_specific=1) | |
1220 if platinc_dir != stdinc_dir: | |
1221 platinc_dest = distutils.sysconfig.get_python_inc( | |
1222 plat_specific=1, prefix=home_dir) | |
1223 if platinc_dir == platinc_dest: | |
1224 # Do platinc_dest manually due to a CPython bug; | |
1225 # not http://bugs.python.org/issue3386 but a close cousin | |
1226 platinc_dest = subst_path(platinc_dir, prefix, home_dir) | |
1227 if platinc_dest: | |
1228 # PyPy's stdinc_dir and prefix are relative to the original binary | |
1229 # (traversing virtualenvs), whereas the platinc_dir is relative to | |
1230 # the inner virtualenv and ignores the prefix argument. | |
1231 # This seems more evolved than designed. | |
1232 copyfile(platinc_dir, platinc_dest, symlink) | |
1233 | |
1234 # pypy never uses exec_prefix, just ignore it | |
1235 if sys.exec_prefix != prefix and not is_pypy: | |
1236 if is_win: | |
1237 exec_dir = join(sys.exec_prefix, 'lib') | |
1238 elif is_jython: | |
1239 exec_dir = join(sys.exec_prefix, 'Lib') | |
1240 else: | |
1241 exec_dir = join(sys.exec_prefix, 'lib', py_version) | |
1242 for fn in os.listdir(exec_dir): | |
1243 copyfile(join(exec_dir, fn), join(lib_dir, fn), symlink) | |
1244 | |
1245 if is_jython: | |
1246 # Jython has either jython-dev.jar and javalib/ dir, or just | |
1247 # jython.jar | |
1248 for name in 'jython-dev.jar', 'javalib', 'jython.jar': | |
1249 src = join(prefix, name) | |
1250 if os.path.exists(src): | |
1251 copyfile(src, join(home_dir, name), symlink) | |
1252 # XXX: registry should always exist after Jython 2.5rc1 | |
1253 src = join(prefix, 'registry') | |
1254 if os.path.exists(src): | |
1255 copyfile(src, join(home_dir, 'registry'), symlink=False) | |
1256 copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'), | |
1257 symlink=False) | |
1258 | |
1259 mkdir(bin_dir) | |
1260 py_executable = join(bin_dir, os.path.basename(sys.executable)) | |
1261 if 'Python.framework' in prefix: | |
1262 # OS X framework builds cause validation to break | |
1263 # https://github.com/pypa/virtualenv/issues/322 | |
1264 if os.environ.get('__PYVENV_LAUNCHER__'): | |
1265 del os.environ["__PYVENV_LAUNCHER__"] | |
1266 if re.search(r'/Python(?:-32|-64)*$', py_executable): | |
1267 # The name of the python executable is not quite what | |
1268 # we want, rename it. | |
1269 py_executable = os.path.join( | |
1270 os.path.dirname(py_executable), 'python') | |
1271 | |
1272 logger.notify('New %s executable in %s', expected_exe, py_executable) | |
1273 pcbuild_dir = os.path.dirname(sys.executable) | |
1274 pyd_pth = os.path.join(lib_dir, 'site-packages', 'virtualenv_builddir_pyd.pt
h') | |
1275 if is_win and os.path.exists(os.path.join(pcbuild_dir, 'build.bat')): | |
1276 logger.notify('Detected python running from build directory %s', pcbuild
_dir) | |
1277 logger.notify('Writing .pth file linking to build directory for *.pyd fi
les') | |
1278 writefile(pyd_pth, pcbuild_dir) | |
1279 else: | |
1280 pcbuild_dir = None | |
1281 if os.path.exists(pyd_pth): | |
1282 logger.info('Deleting %s (not Windows env or not build directory pyt
hon)' % pyd_pth) | |
1283 os.unlink(pyd_pth) | |
1284 | |
1285 if sys.executable != py_executable: | |
1286 ## FIXME: could I just hard link? | |
1287 executable = sys.executable | |
1288 shutil.copyfile(executable, py_executable) | |
1289 make_exe(py_executable) | |
1290 if is_win or is_cygwin: | |
1291 pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe
') | |
1292 if os.path.exists(pythonw): | |
1293 logger.info('Also created pythonw.exe') | |
1294 shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executa
ble), 'pythonw.exe')) | |
1295 python_d = os.path.join(os.path.dirname(sys.executable), 'python_d.e
xe') | |
1296 python_d_dest = os.path.join(os.path.dirname(py_executable), 'python
_d.exe') | |
1297 if os.path.exists(python_d): | |
1298 logger.info('Also created python_d.exe') | |
1299 shutil.copyfile(python_d, python_d_dest) | |
1300 elif os.path.exists(python_d_dest): | |
1301 logger.info('Removed python_d.exe as it is no longer at the sour
ce') | |
1302 os.unlink(python_d_dest) | |
1303 # we need to copy the DLL to enforce that windows will load the corr
ect one. | |
1304 # may not exist if we are cygwin. | |
1305 py_executable_dll = 'python%s%s.dll' % ( | |
1306 sys.version_info[0], sys.version_info[1]) | |
1307 py_executable_dll_d = 'python%s%s_d.dll' % ( | |
1308 sys.version_info[0], sys.version_info[1]) | |
1309 pythondll = os.path.join(os.path.dirname(sys.executable), py_executa
ble_dll) | |
1310 pythondll_d = os.path.join(os.path.dirname(sys.executable), py_execu
table_dll_d) | |
1311 pythondll_d_dest = os.path.join(os.path.dirname(py_executable), py_e
xecutable_dll_d) | |
1312 if os.path.exists(pythondll): | |
1313 logger.info('Also created %s' % py_executable_dll) | |
1314 shutil.copyfile(pythondll, os.path.join(os.path.dirname(py_execu
table), py_executable_dll)) | |
1315 if os.path.exists(pythondll_d): | |
1316 logger.info('Also created %s' % py_executable_dll_d) | |
1317 shutil.copyfile(pythondll_d, pythondll_d_dest) | |
1318 elif os.path.exists(pythondll_d_dest): | |
1319 logger.info('Removed %s as the source does not exist' % pythondl
l_d_dest) | |
1320 os.unlink(pythondll_d_dest) | |
1321 if is_pypy: | |
1322 # make a symlink python --> pypy-c | |
1323 python_executable = os.path.join(os.path.dirname(py_executable), 'py
thon') | |
1324 if sys.platform in ('win32', 'cygwin'): | |
1325 python_executable += '.exe' | |
1326 logger.info('Also created executable %s' % python_executable) | |
1327 copyfile(py_executable, python_executable, symlink) | |
1328 | |
1329 if is_win: | |
1330 for name in ['libexpat.dll', 'libpypy.dll', 'libpypy-c.dll', | |
1331 'libeay32.dll', 'ssleay32.dll', 'sqlite3.dll', | |
1332 'tcl85.dll', 'tk85.dll']: | |
1333 src = join(prefix, name) | |
1334 if os.path.exists(src): | |
1335 copyfile(src, join(bin_dir, name), symlink) | |
1336 | |
1337 for d in sys.path: | |
1338 if d.endswith('lib_pypy'): | |
1339 break | |
1340 else: | |
1341 logger.fatal('Could not find lib_pypy in sys.path') | |
1342 raise SystemExit(3) | |
1343 logger.info('Copying lib_pypy') | |
1344 copyfile(d, os.path.join(home_dir, 'lib_pypy'), symlink) | |
1345 | |
1346 if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe: | |
1347 secondary_exe = os.path.join(os.path.dirname(py_executable), | |
1348 expected_exe) | |
1349 py_executable_ext = os.path.splitext(py_executable)[1] | |
1350 if py_executable_ext.lower() == '.exe': | |
1351 # python2.4 gives an extension of '.4' :P | |
1352 secondary_exe += py_executable_ext | |
1353 if os.path.exists(secondary_exe): | |
1354 logger.warn('Not overwriting existing %s script %s (you must use %s)
' | |
1355 % (expected_exe, secondary_exe, py_executable)) | |
1356 else: | |
1357 logger.notify('Also creating executable in %s' % secondary_exe) | |
1358 shutil.copyfile(sys.executable, secondary_exe) | |
1359 make_exe(secondary_exe) | |
1360 | |
1361 if '.framework' in prefix: | |
1362 if 'Python.framework' in prefix: | |
1363 logger.debug('MacOSX Python framework detected') | |
1364 # Make sure we use the embedded interpreter inside | |
1365 # the framework, even if sys.executable points to | |
1366 # the stub executable in ${sys.prefix}/bin | |
1367 # See http://groups.google.com/group/python-virtualenv/ | |
1368 # browse_thread/thread/17cab2f85da75951 | |
1369 original_python = os.path.join( | |
1370 prefix, 'Resources/Python.app/Contents/MacOS/Python') | |
1371 if 'EPD' in prefix: | |
1372 logger.debug('EPD framework detected') | |
1373 original_python = os.path.join(prefix, 'bin/python') | |
1374 shutil.copy(original_python, py_executable) | |
1375 | |
1376 # Copy the framework's dylib into the virtual | |
1377 # environment | |
1378 virtual_lib = os.path.join(home_dir, '.Python') | |
1379 | |
1380 if os.path.exists(virtual_lib): | |
1381 os.unlink(virtual_lib) | |
1382 copyfile( | |
1383 os.path.join(prefix, 'Python'), | |
1384 virtual_lib, | |
1385 symlink) | |
1386 | |
1387 # And then change the install_name of the copied python executable | |
1388 try: | |
1389 mach_o_change(py_executable, | |
1390 os.path.join(prefix, 'Python'), | |
1391 '@executable_path/../.Python') | |
1392 except: | |
1393 e = sys.exc_info()[1] | |
1394 logger.warn("Could not call mach_o_change: %s. " | |
1395 "Trying to call install_name_tool instead." % e) | |
1396 try: | |
1397 call_subprocess( | |
1398 ["install_name_tool", "-change", | |
1399 os.path.join(prefix, 'Python'), | |
1400 '@executable_path/../.Python', | |
1401 py_executable]) | |
1402 except: | |
1403 logger.fatal("Could not call install_name_tool -- you must " | |
1404 "have Apple's development tools installed") | |
1405 raise | |
1406 | |
1407 if not is_win: | |
1408 # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist | |
1409 py_exe_version_major = 'python%s' % sys.version_info[0] | |
1410 py_exe_version_major_minor = 'python%s.%s' % ( | |
1411 sys.version_info[0], sys.version_info[1]) | |
1412 py_exe_no_version = 'python' | |
1413 required_symlinks = [ py_exe_no_version, py_exe_version_major, | |
1414 py_exe_version_major_minor ] | |
1415 | |
1416 py_executable_base = os.path.basename(py_executable) | |
1417 | |
1418 if py_executable_base in required_symlinks: | |
1419 # Don't try to symlink to yourself. | |
1420 required_symlinks.remove(py_executable_base) | |
1421 | |
1422 for pth in required_symlinks: | |
1423 full_pth = join(bin_dir, pth) | |
1424 if os.path.exists(full_pth): | |
1425 os.unlink(full_pth) | |
1426 if symlink: | |
1427 os.symlink(py_executable_base, full_pth) | |
1428 else: | |
1429 copyfile(py_executable, full_pth, symlink) | |
1430 | |
1431 if is_win and ' ' in py_executable: | |
1432 # There's a bug with subprocess on Windows when using a first | |
1433 # argument that has a space in it. Instead we have to quote | |
1434 # the value: | |
1435 py_executable = '"%s"' % py_executable | |
1436 # NOTE: keep this check as one line, cmd.exe doesn't cope with line breaks | |
1437 cmd = [py_executable, '-c', 'import sys;out=sys.stdout;' | |
1438 'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))'] | |
1439 logger.info('Testing executable with %s %s "%s"' % tuple(cmd)) | |
1440 try: | |
1441 proc = subprocess.Popen(cmd, | |
1442 stdout=subprocess.PIPE) | |
1443 proc_stdout, proc_stderr = proc.communicate() | |
1444 except OSError: | |
1445 e = sys.exc_info()[1] | |
1446 if e.errno == errno.EACCES: | |
1447 logger.fatal('ERROR: The executable %s could not be run: %s' % (py_e
xecutable, e)) | |
1448 sys.exit(100) | |
1449 else: | |
1450 raise e | |
1451 | |
1452 proc_stdout = proc_stdout.strip().decode("utf-8") | |
1453 proc_stdout = os.path.normcase(os.path.abspath(proc_stdout)) | |
1454 norm_home_dir = os.path.normcase(os.path.abspath(home_dir)) | |
1455 if hasattr(norm_home_dir, 'decode'): | |
1456 norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding()) | |
1457 if proc_stdout != norm_home_dir: | |
1458 logger.fatal( | |
1459 'ERROR: The executable %s is not functioning' % py_executable) | |
1460 logger.fatal( | |
1461 'ERROR: It thinks sys.prefix is %r (should be %r)' | |
1462 % (proc_stdout, norm_home_dir)) | |
1463 logger.fatal( | |
1464 'ERROR: virtualenv is not compatible with this system or executable'
) | |
1465 if is_win: | |
1466 logger.fatal( | |
1467 'Note: some Windows users have reported this error when they ' | |
1468 'installed Python for "Only this user" or have multiple ' | |
1469 'versions of Python installed. Copying the appropriate ' | |
1470 'PythonXX.dll to the virtualenv Scripts/ directory may fix ' | |
1471 'this problem.') | |
1472 sys.exit(100) | |
1473 else: | |
1474 logger.info('Got sys.prefix result: %r' % proc_stdout) | |
1475 | |
1476 pydistutils = os.path.expanduser('~/.pydistutils.cfg') | |
1477 if os.path.exists(pydistutils): | |
1478 logger.notify('Please make sure you remove any previous custom paths fro
m ' | |
1479 'your %s file.' % pydistutils) | |
1480 ## FIXME: really this should be calculated earlier | |
1481 | |
1482 fix_local_scheme(home_dir, symlink) | |
1483 | |
1484 if site_packages: | |
1485 if os.path.exists(site_packages_filename): | |
1486 logger.info('Deleting %s' % site_packages_filename) | |
1487 os.unlink(site_packages_filename) | |
1488 | |
1489 return py_executable | |
1490 | |
1491 | |
1492 def install_activate(home_dir, bin_dir, prompt=None): | |
1493 home_dir = os.path.abspath(home_dir) | |
1494 if is_win or is_jython and os._name == 'nt': | |
1495 files = { | |
1496 'activate.bat': ACTIVATE_BAT, | |
1497 'deactivate.bat': DEACTIVATE_BAT, | |
1498 'activate.ps1': ACTIVATE_PS, | |
1499 } | |
1500 | |
1501 # MSYS needs paths of the form /c/path/to/file | |
1502 drive, tail = os.path.splitdrive(home_dir.replace(os.sep, '/')) | |
1503 home_dir_msys = (drive and "/%s%s" or "%s%s") % (drive[:1], tail) | |
1504 | |
1505 # Run-time conditional enables (basic) Cygwin compatibility | |
1506 home_dir_sh = ("""$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '%s'
; else echo '%s'; fi;)""" % | |
1507 (home_dir, home_dir_msys)) | |
1508 files['activate'] = ACTIVATE_SH.replace('__VIRTUAL_ENV__', home_dir_sh) | |
1509 | |
1510 else: | |
1511 files = {'activate': ACTIVATE_SH} | |
1512 | |
1513 # suppling activate.fish in addition to, not instead of, the | |
1514 # bash script support. | |
1515 files['activate.fish'] = ACTIVATE_FISH | |
1516 | |
1517 # same for csh/tcsh support... | |
1518 files['activate.csh'] = ACTIVATE_CSH | |
1519 | |
1520 files['activate_this.py'] = ACTIVATE_THIS | |
1521 if hasattr(home_dir, 'decode'): | |
1522 home_dir = home_dir.decode(sys.getfilesystemencoding()) | |
1523 vname = os.path.basename(home_dir) | |
1524 for name, content in files.items(): | |
1525 content = content.replace('__VIRTUAL_PROMPT__', prompt or '') | |
1526 content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vn
ame) | |
1527 content = content.replace('__VIRTUAL_ENV__', home_dir) | |
1528 content = content.replace('__VIRTUAL_NAME__', vname) | |
1529 content = content.replace('__BIN_NAME__', os.path.basename(bin_dir)) | |
1530 writefile(os.path.join(bin_dir, name), content) | |
1531 | |
1532 def install_distutils(home_dir): | |
1533 distutils_path = change_prefix(distutils.__path__[0], home_dir) | |
1534 mkdir(distutils_path) | |
1535 ## FIXME: maybe this prefix setting should only be put in place if | |
1536 ## there's a local distutils.cfg with a prefix setting? | |
1537 home_dir = os.path.abspath(home_dir) | |
1538 ## FIXME: this is breaking things, removing for now: | |
1539 #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir | |
1540 writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT) | |
1541 writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, over
write=False) | |
1542 | |
1543 def fix_local_scheme(home_dir, symlink=True): | |
1544 """ | |
1545 Platforms that use the "posix_local" install scheme (like Ubuntu with | |
1546 Python 2.7) need to be given an additional "local" location, sigh. | |
1547 """ | |
1548 try: | |
1549 import sysconfig | |
1550 except ImportError: | |
1551 pass | |
1552 else: | |
1553 if sysconfig._get_default_scheme() == 'posix_local': | |
1554 local_path = os.path.join(home_dir, 'local') | |
1555 if not os.path.exists(local_path): | |
1556 os.mkdir(local_path) | |
1557 for subdir_name in os.listdir(home_dir): | |
1558 if subdir_name == 'local': | |
1559 continue | |
1560 copyfile(os.path.abspath(os.path.join(home_dir, subdir_name)
), \ | |
1561 os.path.join(local_p
ath, subdir_name), symlink) | |
1562 | |
1563 def fix_lib64(lib_dir, symlink=True): | |
1564 """ | |
1565 Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y | |
1566 instead of lib/pythonX.Y. If this is such a platform we'll just create a | |
1567 symlink so lib64 points to lib | |
1568 """ | |
1569 if [p for p in distutils.sysconfig.get_config_vars().values() | |
1570 if isinstance(p, basestring) and 'lib64' in p]: | |
1571 # PyPy's library path scheme is not affected by this. | |
1572 # Return early or we will die on the following assert. | |
1573 if is_pypy: | |
1574 logger.debug('PyPy detected, skipping lib64 symlinking') | |
1575 return | |
1576 | |
1577 logger.debug('This system uses lib64; symlinking lib64 to lib') | |
1578 | |
1579 assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], ( | |
1580 "Unexpected python lib dir: %r" % lib_dir) | |
1581 lib_parent = os.path.dirname(lib_dir) | |
1582 top_level = os.path.dirname(lib_parent) | |
1583 lib_dir = os.path.join(top_level, 'lib') | |
1584 lib64_link = os.path.join(top_level, 'lib64') | |
1585 assert os.path.basename(lib_parent) == 'lib', ( | |
1586 "Unexpected parent dir: %r" % lib_parent) | |
1587 if os.path.lexists(lib64_link): | |
1588 return | |
1589 if symlink: | |
1590 os.symlink('lib', lib64_link) | |
1591 else: | |
1592 copyfile('lib', lib64_link) | |
1593 | |
1594 def resolve_interpreter(exe): | |
1595 """ | |
1596 If the executable given isn't an absolute path, search $PATH for the interpr
eter | |
1597 """ | |
1598 # If the "executable" is a version number, get the installed executable for | |
1599 # that version | |
1600 python_versions = get_installed_pythons() | |
1601 if exe in python_versions: | |
1602 exe = python_versions[exe] | |
1603 | |
1604 if os.path.abspath(exe) != exe: | |
1605 paths = os.environ.get('PATH', '').split(os.pathsep) | |
1606 for path in paths: | |
1607 if os.path.exists(os.path.join(path, exe)): | |
1608 exe = os.path.join(path, exe) | |
1609 break | |
1610 if not os.path.exists(exe): | |
1611 logger.fatal('The executable %s (from --python=%s) does not exist' % (ex
e, exe)) | |
1612 raise SystemExit(3) | |
1613 if not is_executable(exe): | |
1614 logger.fatal('The executable %s (from --python=%s) is not executable' %
(exe, exe)) | |
1615 raise SystemExit(3) | |
1616 return exe | |
1617 | |
1618 def is_executable(exe): | |
1619 """Checks a file is executable""" | |
1620 return os.access(exe, os.X_OK) | |
1621 | |
1622 ############################################################ | |
1623 ## Relocating the environment: | |
1624 | |
1625 def make_environment_relocatable(home_dir): | |
1626 """ | |
1627 Makes the already-existing environment use relative paths, and takes out | |
1628 the #!-based environment selection in scripts. | |
1629 """ | |
1630 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) | |
1631 activate_this = os.path.join(bin_dir, 'activate_this.py') | |
1632 if not os.path.exists(activate_this): | |
1633 logger.fatal( | |
1634 'The environment doesn\'t have a file %s -- please re-run virtualenv
' | |
1635 'on this environment to update it' % activate_this) | |
1636 fixup_scripts(home_dir, bin_dir) | |
1637 fixup_pth_and_egg_link(home_dir) | |
1638 ## FIXME: need to fix up distutils.cfg | |
1639 | |
1640 OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3], | |
1641 'activate', 'activate.bat', 'activate_this.py', | |
1642 'activate.fish', 'activate.csh'] | |
1643 | |
1644 def fixup_scripts(home_dir, bin_dir): | |
1645 if is_win: | |
1646 new_shebang_args = ( | |
1647 '%s /c' % os.path.normcase(os.environ.get('COMSPEC', 'cmd.exe')), | |
1648 '', '.exe') | |
1649 else: | |
1650 new_shebang_args = ('/usr/bin/env', sys.version[:3], '') | |
1651 | |
1652 # This is what we expect at the top of scripts: | |
1653 shebang = '#!%s' % os.path.normcase(os.path.join( | |
1654 os.path.abspath(bin_dir), 'python%s' % new_shebang_args[2])) | |
1655 # This is what we'll put: | |
1656 new_shebang = '#!%s python%s%s' % new_shebang_args | |
1657 | |
1658 for filename in os.listdir(bin_dir): | |
1659 filename = os.path.join(bin_dir, filename) | |
1660 if not os.path.isfile(filename): | |
1661 # ignore subdirs, e.g. .svn ones. | |
1662 continue | |
1663 f = open(filename, 'rb') | |
1664 try: | |
1665 try: | |
1666 lines = f.read().decode('utf-8').splitlines() | |
1667 except UnicodeDecodeError: | |
1668 # This is probably a binary program instead | |
1669 # of a script, so just ignore it. | |
1670 continue | |
1671 finally: | |
1672 f.close() | |
1673 if not lines: | |
1674 logger.warn('Script %s is an empty file' % filename) | |
1675 continue | |
1676 | |
1677 old_shebang = lines[0].strip() | |
1678 old_shebang = old_shebang[0:2] + os.path.normcase(old_shebang[2:]) | |
1679 | |
1680 if not old_shebang.startswith(shebang): | |
1681 if os.path.basename(filename) in OK_ABS_SCRIPTS: | |
1682 logger.debug('Cannot make script %s relative' % filename) | |
1683 elif lines[0].strip() == new_shebang: | |
1684 logger.info('Script %s has already been made relative' % filenam
e) | |
1685 else: | |
1686 logger.warn('Script %s cannot be made relative (it\'s not a norm
al script that starts with %s)' | |
1687 % (filename, shebang)) | |
1688 continue | |
1689 logger.notify('Making script %s relative' % filename) | |
1690 script = relative_script([new_shebang] + lines[1:]) | |
1691 f = open(filename, 'wb') | |
1692 f.write('\n'.join(script).encode('utf-8')) | |
1693 f.close() | |
1694 | |
1695 def relative_script(lines): | |
1696 "Return a script that'll work in a relocatable environment." | |
1697 activate = "import os; activate_this=os.path.join(os.path.dirname(os.path.re
alpath(__file__)), 'activate_this.py'); exec(compile(open(activate_this).read(),
activate_this, 'exec'), dict(__file__=activate_this)); del os, activate_this" | |
1698 # Find the last future statement in the script. If we insert the activation | |
1699 # line before a future statement, Python will raise a SyntaxError. | |
1700 activate_at = None | |
1701 for idx, line in reversed(list(enumerate(lines))): | |
1702 if line.split()[:3] == ['from', '__future__', 'import']: | |
1703 activate_at = idx + 1 | |
1704 break | |
1705 if activate_at is None: | |
1706 # Activate after the shebang. | |
1707 activate_at = 1 | |
1708 return lines[:activate_at] + ['', activate, ''] + lines[activate_at:] | |
1709 | |
1710 def fixup_pth_and_egg_link(home_dir, sys_path=None): | |
1711 """Makes .pth and .egg-link files use relative paths""" | |
1712 home_dir = os.path.normcase(os.path.abspath(home_dir)) | |
1713 if sys_path is None: | |
1714 sys_path = sys.path | |
1715 for path in sys_path: | |
1716 if not path: | |
1717 path = '.' | |
1718 if not os.path.isdir(path): | |
1719 continue | |
1720 path = os.path.normcase(os.path.abspath(path)) | |
1721 if not path.startswith(home_dir): | |
1722 logger.debug('Skipping system (non-environment) directory %s' % path
) | |
1723 continue | |
1724 for filename in os.listdir(path): | |
1725 filename = os.path.join(path, filename) | |
1726 if filename.endswith('.pth'): | |
1727 if not os.access(filename, os.W_OK): | |
1728 logger.warn('Cannot write .pth file %s, skipping' % filename
) | |
1729 else: | |
1730 fixup_pth_file(filename) | |
1731 if filename.endswith('.egg-link'): | |
1732 if not os.access(filename, os.W_OK): | |
1733 logger.warn('Cannot write .egg-link file %s, skipping' % fil
ename) | |
1734 else: | |
1735 fixup_egg_link(filename) | |
1736 | |
1737 def fixup_pth_file(filename): | |
1738 lines = [] | |
1739 prev_lines = [] | |
1740 f = open(filename) | |
1741 prev_lines = f.readlines() | |
1742 f.close() | |
1743 for line in prev_lines: | |
1744 line = line.strip() | |
1745 if (not line or line.startswith('#') or line.startswith('import ') | |
1746 or os.path.abspath(line) != line): | |
1747 lines.append(line) | |
1748 else: | |
1749 new_value = make_relative_path(filename, line) | |
1750 if line != new_value: | |
1751 logger.debug('Rewriting path %s as %s (in %s)' % (line, new_valu
e, filename)) | |
1752 lines.append(new_value) | |
1753 if lines == prev_lines: | |
1754 logger.info('No changes to .pth file %s' % filename) | |
1755 return | |
1756 logger.notify('Making paths in .pth file %s relative' % filename) | |
1757 f = open(filename, 'w') | |
1758 f.write('\n'.join(lines) + '\n') | |
1759 f.close() | |
1760 | |
1761 def fixup_egg_link(filename): | |
1762 f = open(filename) | |
1763 link = f.readline().strip() | |
1764 f.close() | |
1765 if os.path.abspath(link) != link: | |
1766 logger.debug('Link in %s already relative' % filename) | |
1767 return | |
1768 new_link = make_relative_path(filename, link) | |
1769 logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link)) | |
1770 f = open(filename, 'w') | |
1771 f.write(new_link) | |
1772 f.close() | |
1773 | |
1774 def make_relative_path(source, dest, dest_is_directory=True): | |
1775 """ | |
1776 Make a filename relative, where the filename is dest, and it is | |
1777 being referred to from the filename source. | |
1778 | |
1779 >>> make_relative_path('/usr/share/something/a-file.pth', | |
1780 ... '/usr/share/another-place/src/Directory') | |
1781 '../another-place/src/Directory' | |
1782 >>> make_relative_path('/usr/share/something/a-file.pth', | |
1783 ... '/home/user/src/Directory') | |
1784 '../../../home/user/src/Directory' | |
1785 >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/') | |
1786 './' | |
1787 """ | |
1788 source = os.path.dirname(source) | |
1789 if not dest_is_directory: | |
1790 dest_filename = os.path.basename(dest) | |
1791 dest = os.path.dirname(dest) | |
1792 dest = os.path.normpath(os.path.abspath(dest)) | |
1793 source = os.path.normpath(os.path.abspath(source)) | |
1794 dest_parts = dest.strip(os.path.sep).split(os.path.sep) | |
1795 source_parts = source.strip(os.path.sep).split(os.path.sep) | |
1796 while dest_parts and source_parts and dest_parts[0] == source_parts[0]: | |
1797 dest_parts.pop(0) | |
1798 source_parts.pop(0) | |
1799 full_parts = ['..']*len(source_parts) + dest_parts | |
1800 if not dest_is_directory: | |
1801 full_parts.append(dest_filename) | |
1802 if not full_parts: | |
1803 # Special case for the current directory (otherwise it'd be '') | |
1804 return './' | |
1805 return os.path.sep.join(full_parts) | |
1806 | |
1807 | |
1808 | |
1809 ############################################################ | |
1810 ## Bootstrap script creation: | |
1811 | |
1812 def create_bootstrap_script(extra_text, python_version=''): | |
1813 """ | |
1814 Creates a bootstrap script, which is like this script but with | |
1815 extend_parser, adjust_options, and after_install hooks. | |
1816 | |
1817 This returns a string that (written to disk of course) can be used | |
1818 as a bootstrap script with your own customizations. The script | |
1819 will be the standard virtualenv.py script, with your extra text | |
1820 added (your extra text should be Python code). | |
1821 | |
1822 If you include these functions, they will be called: | |
1823 | |
1824 ``extend_parser(optparse_parser)``: | |
1825 You can add or remove options from the parser here. | |
1826 | |
1827 ``adjust_options(options, args)``: | |
1828 You can change options here, or change the args (if you accept | |
1829 different kinds of arguments, be sure you modify ``args`` so it is | |
1830 only ``[DEST_DIR]``). | |
1831 | |
1832 ``after_install(options, home_dir)``: | |
1833 | |
1834 After everything is installed, this function is called. This | |
1835 is probably the function you are most likely to use. An | |
1836 example would be:: | |
1837 | |
1838 def after_install(options, home_dir): | |
1839 subprocess.call([join(home_dir, 'bin', 'easy_install'), | |
1840 'MyPackage']) | |
1841 subprocess.call([join(home_dir, 'bin', 'my-package-script'), | |
1842 'setup', home_dir]) | |
1843 | |
1844 This example immediately installs a package, and runs a setup | |
1845 script from that package. | |
1846 | |
1847 If you provide something like ``python_version='2.5'`` then the | |
1848 script will start with ``#!/usr/bin/env python2.5`` instead of | |
1849 ``#!/usr/bin/env python``. You can use this when the script must | |
1850 be run with a particular Python version. | |
1851 """ | |
1852 filename = __file__ | |
1853 if filename.endswith('.pyc'): | |
1854 filename = filename[:-1] | |
1855 f = codecs.open(filename, 'r', encoding='utf-8') | |
1856 content = f.read() | |
1857 f.close() | |
1858 py_exe = 'python%s' % python_version | |
1859 content = (('#!/usr/bin/env %s\n' % py_exe) | |
1860 + '## WARNING: This file is generated\n' | |
1861 + content) | |
1862 return content.replace('##EXT' 'END##', extra_text) | |
1863 | |
1864 ##EXTEND## | |
1865 | |
1866 def convert(s): | |
1867 b = base64.b64decode(s.encode('ascii')) | |
1868 return zlib.decompress(b).decode('utf-8') | |
1869 | |
1870 ##file site.py | |
1871 SITE_PY = convert(""" | |
1872 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 | |
2012 AVijEPwfucjncQ== | |
2013 """) | |
2014 | |
2015 ##file activate.sh | |
2016 ACTIVATE_SH = convert(""" | |
2017 eJytVVFvokAQfudXTLEPtTlLeo9tvMSmJpq02hSvl7u2wRUG2QR2DSxSe7n/frOACEVNLlceRHa+ | |
2018 nfl25pvZDswCnoDPQ4QoTRQsENIEPci4CsBMZBq7CAsuLOYqvmYKTTj3YxnBgiXBudGBjUzBZUJI | |
2019 BXEqgCvweIyuCjeG4eF2F5x14bcB9KQiQQWrjSddI1/oQIx6SYYeoFjzWIoIhYI1izlbhJjkKO7D | |
2020 M/QEmKfO9O7WeRo/zr4P7pyHwWxkwitcgwpQ5Ej96OX+PmiFwLeVjFUOrNYKaq1Nud3nR2n8nI2m | |
2021 k9H0friPTGVsUdptaxGrTEfpNVFEskxpXtUkkCkl1UNF9cgLBkx48J4EXyALuBtAwNYIjF5kcmUU | |
2022 abMKmMq1ULoiRbgsDEkTSsKSGFCJ6Z8vY/2xYiSacmtyAfCDdCNTVZoVF8vSTQOoEwSnOrngBkws | |
2023 MYGMBMg8/bMBLSYKS7pYEXP0PqT+ZmBT0Xuy+Pplj5yn4aM9nk72JD8/Wi+Gr98sD9eWSMOwkapD | |
2024 BbUv91XSvmyVkICt2tmXR4tWmrcUCsjWOpw87YidEC8i0gdTSOFhouJUNxR+4NYBG0MftoCTD9F7 | |
2025 2rTtxG3oPwY1b2HncYwhrlmj6Wq924xtGDWqfdNxap+OYxplEurnMVo9RWks+rH8qKEtx7kZT5zJ | |
2026 4H7oOFclrN6uFe+d+nW2aIUsSgs/42EIPuOhXq+jEo3S6tX6w2ilNkDnIpHCWdEQhFgwj9pkk7FN | |
2027 l/y5eQvRSIQ5+TrL05lewxWpt/Lbhes5cJF3mLET1MGhcKCF+40tNWnUulxrpojwDo2sObdje3Bz | |
2028 N3QeHqf3D7OjEXMVV8LN3ZlvuzoWHqiUcNKHtwNd0IbvPGKYYM31nPKCgkUILw3KL+Y8l7aO1ArS | |
2029 Ad37nIU0fCj5NE5gQCuC5sOSu+UdI2NeXg/lFkQIlFpdWVaWZRfvqGiirC9o6liJ9FXGYrSY9mI1 | |
2030 D/Ncozgn13vJvsznr7DnkJWXsyMH7e42ljdJ+aqNDF1bFnKWFLdj31xtaJYK6EXFgqmV/ymD/ROG | |
2031 +n8O9H8f5vsGOWXsL1+1k3g= | |
2032 """) | |
2033 | |
2034 ##file activate.fish | |
2035 ACTIVATE_FISH = convert(""" | |
2036 eJydVW2P2jgQ/s6vmAZQoVpA9/WkqqJaTou0u6x2uZVOVWWZZEKsS+yc7UDpr+84bziQbauLxEvs | |
2037 eXnsZ56ZIWwTYSAWKUJWGAs7hMJgBEdhEwiMKnSIsBNywUMrDtziPBYmCeBDrFUG7v8HmCTW5n8u | |
2038 Fu7NJJim81Bl08EQTqqAkEupLOhCgrAQCY2hTU+DQVxIiqgkRNiEBphFEKy+kd1BaFvwFOUBuIxA | |
2039 oy20BKtAKp3xFMo0QNtCK5mhtMEA6BmSpUELKo38TThwLfguRVNaiRgs0llnEoIR29zfstf18/bv | |
2040 5T17Wm7vAiiN3ONCzfbfwC3DtWXXDqHfAGX0q6z/bO82j3ebh1VwnbrduwTQbvwcRtesAfMGor/W | |
2041 L3fs6Xnz8LRlm9fV8/P61sM0LDNwCZjl9gSpCokJRzpryGQ5t8kNGFUt51QjOZGu0Mj35FlYlXEr | |
2042 yC09EVOp4lEXfF84Lz1qbhBsgl59vDedXI3rTV03xipduSgt9kLytI3XmBp3aV6MPoMQGNUU62T6 | |
2043 uQdeefTy1Hfj10zVHg2pq8fXDoHBiOv94csfXwN49xECqWREy7pwukKfvxdMY2j23vXDPuuxxeE+ | |
2044 JOdCOhxCE3N44B1ZeSLuZh8Mmkr2wEPAmPfKWHA2uxIRjEopdbQYjDz3BWOf14/scfmwoki1eQvX | |
2045 ExBdF60Mqh+Y/QcX4uiH4Amwzx79KOVFtbL63sXJbtcvy8/3q5rupmO5CnE91wBviQAhjUUegYpL | |
2046 vVEbpLt2/W+PklRgq5Ku6mp+rpMhhCo/lXthQTxJ2ysO4Ka0ad97S7VT/n6YXus6fzk3fLnBZW5C | |
2047 KDC6gSO62QDqgFqLCCtPmjegjnLeAdArtSE8VYGbAJ/aLb+vnQutFhk768E9uRbSxhCMzdgEveYw | |
2048 IZ5ZqFKl6+kz7UR4U+buqQZXu9SIujrAfD7f0FXpozB4Q0gwp31H9mVTZGGC4b871/wm7lvyDLu1 | |
2049 FUyvTj/yvD66k3UPTs08x1AQQaGziOl0S1qRkPG9COtBTSTWM9NzQ4R64B+Px/l3tDzCgxv5C6Ni | |
2050 e+QaF9xFWrxx0V/G5uvYQOdiZzvYpQUVQSIsTr1TTghI33GnPbTA7/GCqcE3oE3GZurq4HeQXQD6 | |
2051 32XS1ITj/qLjN72ob0hc5C9bzw8MhfmL | |
2052 """) | |
2053 | |
2054 ##file activate.csh | |
2055 ACTIVATE_CSH = convert(""" | |
2056 eJx9VG1P2zAQ/u5fcYQKNgTNPtN1WxlIQ4KCUEGaxuQ6yYVYSuzKdhqVX7+zk3bpy5YPUXL3PPfc | |
2057 ne98DLNCWshliVDV1kGCUFvMoJGugMjq2qQIiVSxSJ1cCofD1BYRnOVGV0CfZ0N2DD91DalQSjsw | |
2058 tQLpIJMGU1euvPe7QeJlkKzgWixlhnAt4aoUVsLnLBiy5NtbJWQ5THX1ZciYKKWwkOFaE04dUm6D | |
2059 r/zh7pq/3D7Nnid3/HEy+wFHY/gEJydg0aFaQrBFgz1c5DG1IhTs+UZgsBC2GMFBlaeH+8dZXwcW | |
2060 VPvCjXdlAvCfQsE7al0+07XjZvrSCUevR5dnkVeKlFYZmUztG4BdzL2u9KyLVabTU0bdfg7a0hgs | |
2061 cSmUg6UwUiQl2iHrcbcVGNvPCiLOe7+cRwG13z9qRGgx2z6DHjfm/Op2yqeT+xvOLzs0PTKHDz2V | |
2062 tkckFHoQfQRXoGJAj9el0FyJCmEMhzgMS4sB7KPOE2ExoLcSieYwDvR+cP8cg11gKkVJc2wRcm1g | |
2063 QhYFlXiTaTfO2ki0fQoiFM4tLuO4aZrhOzqR4dIPcWx17hphMBY+Srwh7RTyN83XOWkcSPh1Pg/k | |
2064 TXX/jbJTbMtUmcxZ+/bbqOsy82suFQg/BhdSOTRhMNBHlUarCpU7JzBhmkKmRejKOQzayQe6MWoa | |
2065 n1wqWmuh6LZAaHxcdeqIlVLhIBJdO9/kbl0It2oEXQj+eGjJOuvOIR/YGRqvFhttUB2XTvLXYN2H | |
2066 37CBdbW2W7j2r2+VsCn0doVWcFG1/4y1VwBjfwAyoZhD | |
2067 """) | |
2068 | |
2069 ##file activate.bat | |
2070 ACTIVATE_BAT = convert(""" | |
2071 eJx9UdEKgjAUfW6wfxjiIH+hEDKUFHSKLCMI7kNOEkIf9P9pTJ3OLJ/03HPPPed4Es9XS9qqwqgT | |
2072 PbGKKOdXL4aAFS7A4gvAwgijuiKlqOpGlATS2NeMLE+TjJM9RkQ+SmqAXLrBo1LLIeLdiWlD6jZt | |
2073 r7VNubWkndkXaxg5GO3UaOOKS6drO3luDDiO5my3iA0YAKGzPRV1ack8cOdhysI0CYzIPzjSiH5X | |
2074 0QcvC8Lfaj0emsVKYF2rhL5L3fCkVjV76kShi59NHwDniAHzkgDgqBcwOgTMx+gDQQqXCw== | |
2075 """) | |
2076 | |
2077 ##file deactivate.bat | |
2078 DEACTIVATE_BAT = convert(""" | |
2079 eJxzSE3OyFfIT0vj4ipOLVEI8wwKCXX0iXf1C7Pl4spMU0hJTcvMS01RiPf3cYmHyQYE+fsGhCho | |
2080 cCkAAUibEkTEVhWLMlUlLk6QGixStlyaeCyJDPHw9/Pw93VFsQguim4ZXAJoIUw5DhX47XUM8UCx | |
2081 EchHtwsohN1bILUgw61c/Vy4AJYPYm4= | |
2082 """) | |
2083 | |
2084 ##file activate.ps1 | |
2085 ACTIVATE_PS = convert(""" | |
2086 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 | |
2172 rKQDxR6N/rffXv+lROXet/9Q+l9I4D1U | |
2173 """) | |
2174 | |
2175 ##file distutils-init.py | |
2176 DISTUTILS_INIT = convert(""" | |
2177 eJytV1uL4zYUfvevOE0ottuMW9q3gVDa3aUMXXbLMlDKMBiNrSTqOJKRlMxkf33PkXyRbGe7Dw2E | |
2178 UXTu37lpxLFV2oIyifAncxmOL0xLIfcG+gv80x9VW6maw7o/CANSWWBwFtqeWMPlGY6qPjV8A0bB | |
2179 C4eKSTgZ5LRgFeyErMEeOBhbN+Ipgeizhjtnhkn7DdyjuNLPoCS0l/ayQTG0djwZC08cLXozeMss | |
2180 aG5EzQ0IScpnWtHSTXuxByV/QCmxE7y+eS0uxWeoheaVVfqSJHiU7Mhhi6gULbOHorshkrEnKxpT | |
2181 0n3A8Y8SMpuwZx6aoix3ouFlmW8gHRSkeSJ2g7hU+kiHLDaQw3bmRDaTGfTnty7gPm0FHbIBg9U9 | |
2182 oh1kZzAFLaue2R6htPCtAda2nGlDSUJ4PZBgCJBGVcwKTAMz/vJiLD+Oin5Z5QlvDPdulC6EsiyE | |
2183 NFzb7McNTKJzbJqzphx92VKRFY1idenzmq3K0emRcbWBD0ryqc4NZGmKOOOX9Pz5x+/l27tP797c | |
2184 f/z0d+4NruGNai8uAM0bfsYaw8itFk8ny41jsfpyO+BWlpqfhcG4yxLdi/0tQqoT4a8Vby382mt8 | |
2185 p7XSo7aWGdPBc+b6utaBmCQ7rQKQoWtAuthQCiold2KfJIPTT8xwg9blPumc+YDZC/wYGdAyHpJk | |
2186 vUbHbHWAp5No6pK/WhhLEWrFjUwtPEv1Agf8YmnsuXUQYkeZoHm8ogP16gt2uHoxcEMdf2C6pmbw | |
2187 hUMsWGhanboh4IzzmsIpWs134jVPqD/c74bZHdY69UKKSn/+KfVhxLgUlToemayLMYQOqfEC61bh | |
2188 cbhwaqoGUzIyZRFHPmau5juaWqwRn3mpWmoEA5nhzS5gog/5jbcFQqOZvmBasZtwYlG93k5GEiyw | |
2189 buHhMWLjDarEGpMGB2LFs5nIJkhp/nUmZneFaRth++lieJtHepIvKgx6PJqIlD9X2j6pG1i9x3pZ | |
2190 5bHuCPFiirGHeO7McvoXkz786GaKVzC9DSpnOxJdc4xm6NSVq7lNEnKdVlnpu9BNYoKX2Iq3wvgh | |
2191 gGEUM66kK6j4NiyoneuPLSwaCWDxczgaolEWpiMyDVDb7dNuLAbriL8ig8mmeju31oNvQdpnvEPC | |
2192 1vAXbWacGRVrGt/uXN/gU0CDDwgooKRrHfTBb1/s9lYZ8ZqOBU0yLvpuP6+K9hLFsvIjeNhBi0KL | |
2193 MlOuWRn3FRwx5oHXjl0YImUx0+gLzjGchrgzca026ETmYJzPD+IpuKzNi8AFn048Thd63OdD86M6 | |
2194 84zE8yQm0VqXdbbgvub2pKVnS76icBGdeTHHXTKspUmr4NYo/furFLKiMdQzFjHJNcdAnMhltBJK | |
2195 0/IKX3DVFqvPJ2dLE7bDBkH0l/PJ29074+F0CsGYOxsb7U3myTUncYfXqnLLfa6sJybX4g+hmcjO | |
2196 kMRBfA1JellfRRKJcyRpxdS4rIl6FdmQCWjo/o9Qz7yKffoP4JHjOvABcRn4CZIT2RH4jnxmfpVG | |
2197 qgLaAvQBNfuO6X0/Ux02nb4FKx3vgP+XnkX0QW9pLy/NsXgdN24dD3LxO2Nwil7Zlc1dqtP3d7/h | |
2198 kzp1/+7hGBuY4pk0XD/0Ao/oTe/XGrfyM773aB7iUhgkpy+dwAMalxMP0DrBcsVw/6p25+/hobP9 | |
2199 GBknrWExDhLJ1bwt1NcCNblaFbMKCyvmX0PeRaQ= | |
2200 """) | |
2201 | |
2202 ##file distutils.cfg | |
2203 DISTUTILS_CFG = convert(""" | |
2204 eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH | |
2205 xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg | |
2206 9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q= | |
2207 """) | |
2208 | |
2209 ##file activate_this.py | |
2210 ACTIVATE_THIS = convert(""" | |
2211 eJyNU01v2zAMvetXEB4K21jnDOstQA4dMGCHbeihlyEIDMWmE62yJEiKE//7kXKdpEWLzYBt8evx | |
2212 kRSzLPs6wiEoswM8YdMpjUXcq1Dz6RZa1cSiTkJdr86GsoTRHuCotBayiWqQEYGtMCgfD1KjGYBe | |
2213 5a3p0cRKiEe2NtLAFikftnDco0ko/SFEVgEZ8aRCZDIPY9xbA8pE9M4jfW/B2CjiHq9zbJVZuOQq | |
2214 siwTIvpxKYCembPAU4Muwi/Z4zfvrZ/MXipKeB8C+qisSZYiWfjJfs+0/MFMdWn1hJcO5U7G/SLa | |
2215 xVx8zU6VG/PXLXvfsyyzUqjeWR8hjGE+2iCE1W1tQ82hsCJN9dzKaoexyB/uH79TnjwvxcW0ntSb | |
2216 yZ8jq1Z5Q1UXsyy3gf9nbjTEj7NzQMfCJa/YSmrQ+2D/BqfiOi6sclrGzvoeVivIj8rcfcmnIQRF | |
2217 7XCyeZI7DFe5/lhlCs5PRf5QW66VXT/NrlQ46oD/D6InkOmi3IQcbhKxAX2g4a+Xd5s3UtCtG2py | |
2218 m8eg6WYWqR6SL5OjKMGfSrYt/6kxxQtOpeAgj1LXBNmpE2ElmCSIy5H0zFd8gJ924HWijWhb2hRC | |
2219 6wNEm1QdDZtuSZcEprIUBo/XRNcbQe1OUbQ/r3hPTaPJJDNtFLu8KHV5XoNr3Eo6h6YtOKw8e8yw | |
2220 VF5PnJ+ts3a9/Mz38RpG/AUSzYUW | |
2221 """) | |
2222 | |
2223 MH_MAGIC = 0xfeedface | |
2224 MH_CIGAM = 0xcefaedfe | |
2225 MH_MAGIC_64 = 0xfeedfacf | |
2226 MH_CIGAM_64 = 0xcffaedfe | |
2227 FAT_MAGIC = 0xcafebabe | |
2228 BIG_ENDIAN = '>' | |
2229 LITTLE_ENDIAN = '<' | |
2230 LC_LOAD_DYLIB = 0xc | |
2231 maxint = majver == 3 and getattr(sys, 'maxsize') or getattr(sys, 'maxint') | |
2232 | |
2233 | |
2234 class fileview(object): | |
2235 """ | |
2236 A proxy for file-like objects that exposes a given view of a file. | |
2237 Modified from macholib. | |
2238 """ | |
2239 | |
2240 def __init__(self, fileobj, start=0, size=maxint): | |
2241 if isinstance(fileobj, fileview): | |
2242 self._fileobj = fileobj._fileobj | |
2243 else: | |
2244 self._fileobj = fileobj | |
2245 self._start = start | |
2246 self._end = start + size | |
2247 self._pos = 0 | |
2248 | |
2249 def __repr__(self): | |
2250 return '<fileview [%d, %d] %r>' % ( | |
2251 self._start, self._end, self._fileobj) | |
2252 | |
2253 def tell(self): | |
2254 return self._pos | |
2255 | |
2256 def _checkwindow(self, seekto, op): | |
2257 if not (self._start <= seekto <= self._end): | |
2258 raise IOError("%s to offset %d is outside window [%d, %d]" % ( | |
2259 op, seekto, self._start, self._end)) | |
2260 | |
2261 def seek(self, offset, whence=0): | |
2262 seekto = offset | |
2263 if whence == os.SEEK_SET: | |
2264 seekto += self._start | |
2265 elif whence == os.SEEK_CUR: | |
2266 seekto += self._start + self._pos | |
2267 elif whence == os.SEEK_END: | |
2268 seekto += self._end | |
2269 else: | |
2270 raise IOError("Invalid whence argument to seek: %r" % (whence,)) | |
2271 self._checkwindow(seekto, 'seek') | |
2272 self._fileobj.seek(seekto) | |
2273 self._pos = seekto - self._start | |
2274 | |
2275 def write(self, bytes): | |
2276 here = self._start + self._pos | |
2277 self._checkwindow(here, 'write') | |
2278 self._checkwindow(here + len(bytes), 'write') | |
2279 self._fileobj.seek(here, os.SEEK_SET) | |
2280 self._fileobj.write(bytes) | |
2281 self._pos += len(bytes) | |
2282 | |
2283 def read(self, size=maxint): | |
2284 assert size >= 0 | |
2285 here = self._start + self._pos | |
2286 self._checkwindow(here, 'read') | |
2287 size = min(size, self._end - here) | |
2288 self._fileobj.seek(here, os.SEEK_SET) | |
2289 bytes = self._fileobj.read(size) | |
2290 self._pos += len(bytes) | |
2291 return bytes | |
2292 | |
2293 | |
2294 def read_data(file, endian, num=1): | |
2295 """ | |
2296 Read a given number of 32-bits unsigned integers from the given file | |
2297 with the given endianness. | |
2298 """ | |
2299 res = struct.unpack(endian + 'L' * num, file.read(num * 4)) | |
2300 if len(res) == 1: | |
2301 return res[0] | |
2302 return res | |
2303 | |
2304 | |
2305 def mach_o_change(path, what, value): | |
2306 """ | |
2307 Replace a given name (what) in any LC_LOAD_DYLIB command found in | |
2308 the given binary with a new name (value), provided it's shorter. | |
2309 """ | |
2310 | |
2311 def do_macho(file, bits, endian): | |
2312 # Read Mach-O header (the magic number is assumed read by the caller) | |
2313 cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = read_data(file
, endian, 6) | |
2314 # 64-bits header has one more field. | |
2315 if bits == 64: | |
2316 read_data(file, endian) | |
2317 # The header is followed by ncmds commands | |
2318 for n in range(ncmds): | |
2319 where = file.tell() | |
2320 # Read command header | |
2321 cmd, cmdsize = read_data(file, endian, 2) | |
2322 if cmd == LC_LOAD_DYLIB: | |
2323 # The first data field in LC_LOAD_DYLIB commands is the | |
2324 # offset of the name, starting from the beginning of the | |
2325 # command. | |
2326 name_offset = read_data(file, endian) | |
2327 file.seek(where + name_offset, os.SEEK_SET) | |
2328 # Read the NUL terminated string | |
2329 load = file.read(cmdsize - name_offset).decode() | |
2330 load = load[:load.index('\0')] | |
2331 # If the string is what is being replaced, overwrite it. | |
2332 if load == what: | |
2333 file.seek(where + name_offset, os.SEEK_SET) | |
2334 file.write(value.encode() + '\0'.encode()) | |
2335 # Seek to the next command | |
2336 file.seek(where + cmdsize, os.SEEK_SET) | |
2337 | |
2338 def do_file(file, offset=0, size=maxint): | |
2339 file = fileview(file, offset, size) | |
2340 # Read magic number | |
2341 magic = read_data(file, BIG_ENDIAN) | |
2342 if magic == FAT_MAGIC: | |
2343 # Fat binaries contain nfat_arch Mach-O binaries | |
2344 nfat_arch = read_data(file, BIG_ENDIAN) | |
2345 for n in range(nfat_arch): | |
2346 # Read arch header | |
2347 cputype, cpusubtype, offset, size, align = read_data(file, BIG_E
NDIAN, 5) | |
2348 do_file(file, offset, size) | |
2349 elif magic == MH_MAGIC: | |
2350 do_macho(file, 32, BIG_ENDIAN) | |
2351 elif magic == MH_CIGAM: | |
2352 do_macho(file, 32, LITTLE_ENDIAN) | |
2353 elif magic == MH_MAGIC_64: | |
2354 do_macho(file, 64, BIG_ENDIAN) | |
2355 elif magic == MH_CIGAM_64: | |
2356 do_macho(file, 64, LITTLE_ENDIAN) | |
2357 | |
2358 assert(len(what) >= len(value)) | |
2359 do_file(open(path, 'r+b')) | |
2360 | |
2361 | |
2362 if __name__ == '__main__': | |
2363 main() | |
2364 | |
2365 ## TODO: | |
2366 ## Copy python.exe.manifest | |
2367 ## Monkeypatch distutils.sysconfig | |
OLD | NEW |