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