blob: ba357fd5ea05a799770295d3a980d286322a3c4f [file] [log] [blame]
Tor Norbye3a2425a2013-11-04 10:16:08 -08001#!/usr/bin/env python
2"""Create a "virtual" Python installation
3"""
4
5__version__ = "1.10.1"
6virtualenv_version = __version__ # legacy
7
8import base64
9import sys
10import os
11import codecs
12import optparse
13import re
14import shutil
15import logging
16import tempfile
17import zlib
18import errno
19import glob
20import distutils.sysconfig
21from distutils.util import strtobool
22import struct
23import subprocess
24import tarfile
25
26if 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)
30
31try:
32 set
33except NameError:
34 from sets import Set as set
35try:
36 basestring
37except NameError:
38 basestring = str
39
40try:
41 import ConfigParser
42except ImportError:
43 import configparser as ConfigParser
44
45join = os.path.join
46py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
47
48is_jython = sys.platform.startswith('java')
49is_pypy = hasattr(sys, 'pypy_version_info')
50is_win = (sys.platform == 'win32')
51is_cygwin = (sys.platform == 'cygwin')
52is_darwin = (sys.platform == 'darwin')
53abiflags = getattr(sys, 'abiflags', '')
54
55user_dir = os.path.expanduser('~')
56if is_win:
57 default_storage_dir = os.path.join(user_dir, 'virtualenv')
58else:
59 default_storage_dir = os.path.join(user_dir, '.virtualenv')
60default_config_file = os.path.join(default_storage_dir, 'virtualenv.ini')
61
62if is_pypy:
63 expected_exe = 'pypy'
64elif is_jython:
65 expected_exe = 'jython'
66else:
67 expected_exe = 'python'
68
69# Return a mapping of version -> Python executable
70# Only provided for Windows, where the information in the registry is used
71if not is_win:
72 def get_installed_pythons():
73 return {}
74else:
75 try:
76 import winreg
77 except ImportError:
78 import _winreg as winreg
79
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")
95
96 winreg.CloseKey(python_core)
97
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]
103
104 return exes
105
106REQUIRED_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']
111
112REQUIRED_FILES = ['lib-dynload', 'config']
113
114majver, minver = sys.version_info[:2]
115if 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__'])
122elif 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
289if is_pypy:
290 # these are needed to correctly display the exceptions that may happen
291 # during the bootstrap
292 REQUIRED_MODULES.extend(['traceback', 'linecache'])
293
294class Logger(object):
295
296 """
297 Logging object for use in command-line script. Allows ranges of
298 levels, to avoid some redundancy of displayed information.
299 """
300
301 DEBUG = logging.DEBUG
302 INFO = logging.INFO
303 NOTIFY = (logging.INFO+logging.WARN)/2
304 WARN = WARNING = logging.WARN
305 ERROR = logging.ERROR
306 FATAL = logging.FATAL
307
308 LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
309
310 def __init__(self, consumers):
311 self.consumers = consumers
312 self.indent = 0
313 self.in_progress = None
314 self.in_progress_hanging = False
315
316 def debug(self, msg, *args, **kw):
317 self.log(self.DEBUG, msg, *args, **kw)
318 def info(self, msg, *args, **kw):
319 self.log(self.INFO, msg, *args, **kw)
320 def notify(self, msg, *args, **kw):
321 self.log(self.NOTIFY, msg, *args, **kw)
322 def warn(self, msg, *args, **kw):
323 self.log(self.WARN, msg, *args, **kw)
324 def error(self, msg, *args, **kw):
325 self.log(self.ERROR, msg, *args, **kw)
326 def fatal(self, msg, *args, **kw):
327 self.log(self.FATAL, msg, *args, **kw)
328 def log(self, level, msg, *args, **kw):
329 if args:
330 if kw:
331 raise TypeError(
332 "You may give positional or keyword arguments, not both")
333 args = args or kw
334 rendered = None
335 for consumer_level, consumer in self.consumers:
336 if self.level_matches(level, consumer_level):
337 if (self.in_progress_hanging
338 and consumer in (sys.stdout, sys.stderr)):
339 self.in_progress_hanging = False
340 sys.stdout.write('\n')
341 sys.stdout.flush()
342 if rendered is None:
343 if args:
344 rendered = msg % args
345 else:
346 rendered = msg
347 rendered = ' '*self.indent + rendered
348 if hasattr(consumer, 'write'):
349 consumer.write(rendered+'\n')
350 else:
351 consumer(rendered)
352
353 def start_progress(self, msg):
354 assert not self.in_progress, (
355 "Tried to start_progress(%r) while in_progress %r"
356 % (msg, self.in_progress))
357 if self.level_matches(self.NOTIFY, self._stdout_level()):
358 sys.stdout.write(msg)
359 sys.stdout.flush()
360 self.in_progress_hanging = True
361 else:
362 self.in_progress_hanging = False
363 self.in_progress = msg
364
365 def end_progress(self, msg='done.'):
366 assert self.in_progress, (
367 "Tried to end_progress without start_progress")
368 if self.stdout_level_matches(self.NOTIFY):
369 if not self.in_progress_hanging:
370 # Some message has been printed out since start_progress
371 sys.stdout.write('...' + self.in_progress + msg + '\n')
372 sys.stdout.flush()
373 else:
374 sys.stdout.write(msg + '\n')
375 sys.stdout.flush()
376 self.in_progress = None
377 self.in_progress_hanging = False
378
379 def show_progress(self):
380 """If we are in a progress scope, and no log messages have been
381 shown, write out another '.'"""
382 if self.in_progress_hanging:
383 sys.stdout.write('.')
384 sys.stdout.flush()
385
386 def stdout_level_matches(self, level):
387 """Returns true if a message at this level will go to stdout"""
388 return self.level_matches(level, self._stdout_level())
389
390 def _stdout_level(self):
391 """Returns the level that stdout runs at"""
392 for level, consumer in self.consumers:
393 if consumer is sys.stdout:
394 return level
395 return self.FATAL
396
397 def level_matches(self, level, consumer_level):
398 """
399 >>> l = Logger([])
400 >>> l.level_matches(3, 4)
401 False
402 >>> l.level_matches(3, 2)
403 True
404 >>> l.level_matches(slice(None, 3), 3)
405 False
406 >>> l.level_matches(slice(None, 3), 2)
407 True
408 >>> l.level_matches(slice(1, 3), 1)
409 True
410 >>> l.level_matches(slice(2, 3), 1)
411 False
412 """
413 if isinstance(level, slice):
414 start, stop = level.start, level.stop
415 if start is not None and start > consumer_level:
416 return False
417 if stop is not None and stop <= consumer_level:
418 return False
419 return True
420 else:
421 return level >= consumer_level
422
423 #@classmethod
424 def level_for_integer(cls, level):
425 levels = cls.LEVELS
426 if level < 0:
427 return levels[0]
428 if level >= len(levels):
429 return levels[-1]
430 return levels[level]
431
432 level_for_integer = classmethod(level_for_integer)
433
434# create a silent logger just to prevent this from being undefined
435# will be overridden with requested verbosity main() is called.
436logger = Logger([(Logger.LEVELS[-1], sys.stdout)])
437
438def mkdir(path):
439 if not os.path.exists(path):
440 logger.info('Creating %s', path)
441 os.makedirs(path)
442 else:
443 logger.info('Directory %s already exists', path)
444
445def copyfileordir(src, dest, symlink=True):
446 if os.path.isdir(src):
447 shutil.copytree(src, dest, symlink)
448 else:
449 shutil.copy2(src, dest)
450
451def copyfile(src, dest, symlink=True):
452 if not os.path.exists(src):
453 # Some bad symlink in the src
454 logger.warn('Cannot find file %s (bad symlink)', src)
455 return
456 if os.path.exists(dest):
457 logger.debug('File %s already exists', dest)
458 return
459 if not os.path.exists(os.path.dirname(dest)):
460 logger.info('Creating parent directories for %s', os.path.dirname(dest))
461 os.makedirs(os.path.dirname(dest))
462 if not os.path.islink(src):
463 srcpath = os.path.abspath(src)
464 else:
465 srcpath = os.readlink(src)
466 if symlink and hasattr(os, 'symlink') and not is_win:
467 logger.info('Symlinking %s', dest)
468 try:
469 os.symlink(srcpath, dest)
470 except (OSError, NotImplementedError):
471 logger.info('Symlinking failed, copying to %s', dest)
472 copyfileordir(src, dest, symlink)
473 else:
474 logger.info('Copying to %s', dest)
475 copyfileordir(src, dest, symlink)
476
477def writefile(dest, content, overwrite=True):
478 if not os.path.exists(dest):
479 logger.info('Writing %s', dest)
480 f = open(dest, 'wb')
481 f.write(content.encode('utf-8'))
482 f.close()
483 return
484 else:
485 f = open(dest, 'rb')
486 c = f.read()
487 f.close()
488 if c != content.encode("utf-8"):
489 if not overwrite:
490 logger.notify('File %s exists with different content; not overwriting', dest)
491 return
492 logger.notify('Overwriting %s with new content', dest)
493 f = open(dest, 'wb')
494 f.write(content.encode('utf-8'))
495 f.close()
496 else:
497 logger.info('Content %s already in place', dest)
498
499def rmtree(dir):
500 if os.path.exists(dir):
501 logger.notify('Deleting tree %s', dir)
502 shutil.rmtree(dir)
503 else:
504 logger.info('Do not need to delete %s; already gone', dir)
505
506def make_exe(fn):
507 if hasattr(os, 'chmod'):
508 oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777
509 newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777
510 os.chmod(fn, newmode)
511 logger.info('Changed mode of %s to %s', fn, oct(newmode))
512
513def _find_file(filename, dirs):
514 for dir in reversed(dirs):
515 files = glob.glob(os.path.join(dir, filename))
516 if files and os.path.isfile(files[0]):
517 return True, files[0]
518 return False, filename
519
520def file_search_dirs():
521 here = os.path.dirname(os.path.abspath(__file__))
522 dirs = ['.', here,
523 join(here, 'virtualenv_support')]
524 if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
525 # Probably some boot script; just in case virtualenv is installed...
526 try:
527 import virtualenv
528 except ImportError:
529 pass
530 else:
531 dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
532 return [d for d in dirs if os.path.isdir(d)]
533
534
535class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter):
536 """
537 Custom help formatter for use in ConfigOptionParser that updates
538 the defaults before expanding them, allowing them to show up correctly
539 in the help listing
540 """
541 def expand_default(self, option):
542 if self.parser is not None:
543 self.parser.update_defaults(self.parser.defaults)
544 return optparse.IndentedHelpFormatter.expand_default(self, option)
545
546
547class ConfigOptionParser(optparse.OptionParser):
548 """
549 Custom option parser which updates its defaults by checking the
550 configuration files and environmental variables
551 """
552 def __init__(self, *args, **kwargs):
553 self.config = ConfigParser.RawConfigParser()
554 self.files = self.get_config_files()
555 self.config.read(self.files)
556 optparse.OptionParser.__init__(self, *args, **kwargs)
557
558 def get_config_files(self):
559 config_file = os.environ.get('VIRTUALENV_CONFIG_FILE', False)
560 if config_file and os.path.exists(config_file):
561 return [config_file]
562 return [default_config_file]
563
564 def update_defaults(self, defaults):
565 """
566 Updates the given defaults with values from the config files and
567 the environ. Does a little special handling for certain types of
568 options (lists).
569 """
570 # Then go and look for the other sources of configuration:
571 config = {}
572 # 1. config files
573 config.update(dict(self.get_config_section('virtualenv')))
574 # 2. environmental variables
575 config.update(dict(self.get_environ_vars()))
576 # Then set the options with those values
577 for key, val in config.items():
578 key = key.replace('_', '-')
579 if not key.startswith('--'):
580 key = '--%s' % key # only prefer long opts
581 option = self.get_option(key)
582 if option is not None:
583 # ignore empty values
584 if not val:
585 continue
586 # handle multiline configs
587 if option.action == 'append':
588 val = val.split()
589 else:
590 option.nargs = 1
591 if option.action == 'store_false':
592 val = not strtobool(val)
593 elif option.action in ('store_true', 'count'):
594 val = strtobool(val)
595 try:
596 val = option.convert_value(key, val)
597 except optparse.OptionValueError:
598 e = sys.exc_info()[1]
599 print("An error occured during configuration: %s" % e)
600 sys.exit(3)
601 defaults[option.dest] = val
602 return defaults
603
604 def get_config_section(self, name):
605 """
606 Get a section of a configuration
607 """
608 if self.config.has_section(name):
609 return self.config.items(name)
610 return []
611
612 def get_environ_vars(self, prefix='VIRTUALENV_'):
613 """
614 Returns a generator with all environmental vars with prefix VIRTUALENV
615 """
616 for key, val in os.environ.items():
617 if key.startswith(prefix):
618 yield (key.replace(prefix, '').lower(), val)
619
620 def get_default_values(self):
621 """
622 Overridding to make updating the defaults after instantiation of
623 the option parser possible, update_defaults() does the dirty work.
624 """
625 if not self.process_default_values:
626 # Old, pre-Optik 1.5 behaviour.
627 return optparse.Values(self.defaults)
628
629 defaults = self.update_defaults(self.defaults.copy()) # ours
630 for option in self._get_all_options():
631 default = defaults.get(option.dest)
632 if isinstance(default, basestring):
633 opt_str = option.get_opt_string()
634 defaults[option.dest] = option.check_value(opt_str, default)
635 return optparse.Values(defaults)
636
637
638def main():
639 parser = ConfigOptionParser(
640 version=virtualenv_version,
641 usage="%prog [OPTIONS] DEST_DIR",
642 formatter=UpdatingDefaultsHelpFormatter())
643
644 parser.add_option(
645 '-v', '--verbose',
646 action='count',
647 dest='verbose',
648 default=0,
649 help="Increase verbosity")
650
651 parser.add_option(
652 '-q', '--quiet',
653 action='count',
654 dest='quiet',
655 default=0,
656 help='Decrease verbosity')
657
658 parser.add_option(
659 '-p', '--python',
660 dest='python',
661 metavar='PYTHON_EXE',
662 help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
663 'interpreter to create the new environment. The default is the interpreter that '
664 'virtualenv was installed with (%s)' % sys.executable)
665
666 parser.add_option(
667 '--clear',
668 dest='clear',
669 action='store_true',
670 help="Clear out the non-root install and start from scratch")
671
672 parser.set_defaults(system_site_packages=False)
673 parser.add_option(
674 '--no-site-packages',
675 dest='system_site_packages',
676 action='store_false',
677 help="Don't give access to the global site-packages dir to the "
678 "virtual environment (default)")
679
680 parser.add_option(
681 '--system-site-packages',
682 dest='system_site_packages',
683 action='store_true',
684 help="Give access to the global site-packages dir to the "
685 "virtual environment")
686
687 parser.add_option(
688 '--always-copy',
689 dest='symlink',
690 action='store_false',
691 default=True,
692 help="Always copy files rather than symlinking")
693
694 parser.add_option(
695 '--unzip-setuptools',
696 dest='unzip_setuptools',
697 action='store_true',
698 help="Unzip Setuptools when installing it")
699
700 parser.add_option(
701 '--relocatable',
702 dest='relocatable',
703 action='store_true',
704 help='Make an EXISTING virtualenv environment relocatable. '
705 'This fixes up scripts and makes all .pth files relative')
706
707 parser.add_option(
708 '--no-setuptools',
709 dest='no_setuptools',
710 action='store_true',
711 help='Do not install setuptools (or pip) '
712 'in the new virtualenv.')
713
714 parser.add_option(
715 '--no-pip',
716 dest='no_pip',
717 action='store_true',
718 help='Do not install pip in the new virtualenv.')
719
720 default_search_dirs = file_search_dirs()
721 parser.add_option(
722 '--extra-search-dir',
723 dest="search_dirs",
724 action="append",
725 default=default_search_dirs,
726 help="Directory to look for setuptools/pip distributions in. "
727 "You can add any number of additional --extra-search-dir paths.")
728
729 parser.add_option(
730 '--never-download',
731 dest="never_download",
732 action="store_true",
733 default=True,
734 help="Never download anything from the network. This is now always "
735 "the case. The option is only retained for backward compatibility, "
736 "and does nothing. Virtualenv will fail if local distributions "
737 "of setuptools/pip are not present.")
738
739 parser.add_option(
740 '--prompt',
741 dest='prompt',
742 help='Provides an alternative prompt prefix for this environment')
743
744 parser.add_option(
745 '--setuptools',
746 dest='setuptools',
747 action='store_true',
748 help="Backward compatibility. Does nothing.")
749
750 parser.add_option(
751 '--distribute',
752 dest='distribute',
753 action='store_true',
754 help="Backward compatibility. Does nothing.")
755
756 if 'extend_parser' in globals():
757 extend_parser(parser)
758
759 options, args = parser.parse_args()
760
761 global logger
762
763 if 'adjust_options' in globals():
764 adjust_options(options, args)
765
766 verbosity = options.verbose - options.quiet
767 logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)])
768
769 if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
770 env = os.environ.copy()
771 interpreter = resolve_interpreter(options.python)
772 if interpreter == sys.executable:
773 logger.warn('Already using interpreter %s' % interpreter)
774 else:
775 logger.notify('Running virtualenv with interpreter %s' % interpreter)
776 env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
777 file = __file__
778 if file.endswith('.pyc'):
779 file = file[:-1]
780 popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
781 raise SystemExit(popen.wait())
782
783 if not args:
784 print('You must provide a DEST_DIR')
785 parser.print_help()
786 sys.exit(2)
787 if len(args) > 1:
788 print('There must be only one argument: DEST_DIR (you gave %s)' % (
789 ' '.join(args)))
790 parser.print_help()
791 sys.exit(2)
792
793 home_dir = args[0]
794
795 if os.environ.get('WORKING_ENV'):
796 logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
797 logger.fatal('Please deactivate your workingenv, then re-run this script')
798 sys.exit(3)
799
800 if 'PYTHONHOME' in os.environ:
801 logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it')
802 del os.environ['PYTHONHOME']
803
804 if options.relocatable:
805 make_environment_relocatable(home_dir)
806 return
807
808 if not options.never_download:
809 logger.warn('The --never-download option is for backward compatibility only.')
810 logger.warn('Setting it to false is no longer supported, and will be ignored.')
811
812 create_environment(home_dir,
813 site_packages=options.system_site_packages,
814 clear=options.clear,
815 unzip_setuptools=options.unzip_setuptools,
816 prompt=options.prompt,
817 search_dirs=options.search_dirs,
818 never_download=True,
819 no_setuptools=options.no_setuptools,
820 no_pip=options.no_pip,
821 symlink=options.symlink)
822 if 'after_install' in globals():
823 after_install(options, home_dir)
824
825def call_subprocess(cmd, show_stdout=True,
826 filter_stdout=None, cwd=None,
827 raise_on_returncode=True, extra_env=None,
828 remove_from_env=None):
829 cmd_parts = []
830 for part in cmd:
831 if len(part) > 45:
832 part = part[:20]+"..."+part[-20:]
833 if ' ' in part or '\n' in part or '"' in part or "'" in part:
834 part = '"%s"' % part.replace('"', '\\"')
835 if hasattr(part, 'decode'):
836 try:
837 part = part.decode(sys.getdefaultencoding())
838 except UnicodeDecodeError:
839 part = part.decode(sys.getfilesystemencoding())
840 cmd_parts.append(part)
841 cmd_desc = ' '.join(cmd_parts)
842 if show_stdout:
843 stdout = None
844 else:
845 stdout = subprocess.PIPE
846 logger.debug("Running command %s" % cmd_desc)
847 if extra_env or remove_from_env:
848 env = os.environ.copy()
849 if extra_env:
850 env.update(extra_env)
851 if remove_from_env:
852 for varname in remove_from_env:
853 env.pop(varname, None)
854 else:
855 env = None
856 try:
857 proc = subprocess.Popen(
858 cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
859 cwd=cwd, env=env)
860 except Exception:
861 e = sys.exc_info()[1]
862 logger.fatal(
863 "Error %s while executing command %s" % (e, cmd_desc))
864 raise
865 all_output = []
866 if stdout is not None:
867 stdout = proc.stdout
868 encoding = sys.getdefaultencoding()
869 fs_encoding = sys.getfilesystemencoding()
870 while 1:
871 line = stdout.readline()
872 try:
873 line = line.decode(encoding)
874 except UnicodeDecodeError:
875 line = line.decode(fs_encoding)
876 if not line:
877 break
878 line = line.rstrip()
879 all_output.append(line)
880 if filter_stdout:
881 level = filter_stdout(line)
882 if isinstance(level, tuple):
883 level, line = level
884 logger.log(level, line)
885 if not logger.stdout_level_matches(level):
886 logger.show_progress()
887 else:
888 logger.info(line)
889 else:
890 proc.communicate()
891 proc.wait()
892 if proc.returncode:
893 if raise_on_returncode:
894 if all_output:
895 logger.notify('Complete output from command %s:' % cmd_desc)
896 logger.notify('\n'.join(all_output) + '\n----------------------------------------')
897 raise OSError(
898 "Command %s failed with error code %s"
899 % (cmd_desc, proc.returncode))
900 else:
901 logger.warn(
902 "Command %s had error code %s"
903 % (cmd_desc, proc.returncode))
904
905def filter_install_output(line):
906 if line.strip().startswith('running'):
907 return Logger.INFO
908 return Logger.DEBUG
909
910def install_sdist(project_name, sdist, py_executable, search_dirs=None):
911
912 if search_dirs is None:
913 search_dirs = file_search_dirs()
914 found, sdist_path = _find_file(sdist, search_dirs)
915 if not found:
916 logger.fatal("Cannot find sdist %s" % (sdist,))
917 return
918
919 tmpdir = tempfile.mkdtemp()
920 try:
921 tar = tarfile.open(sdist_path)
922 tar.extractall(tmpdir)
923 tar.close()
924 srcdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
925 cmd = [py_executable, 'setup.py', 'install',
926 '--single-version-externally-managed',
927 '--record', 'record']
928 logger.start_progress('Installing %s...' % project_name)
929 logger.indent += 2
930 try:
931 call_subprocess(cmd, show_stdout=False, cwd=srcdir,
932 filter_stdout=filter_install_output)
933 finally:
934 logger.indent -= 2
935 logger.end_progress()
936 finally:
937 shutil.rmtree(tmpdir)
938
939def create_environment(home_dir, site_packages=False, clear=False,
940 unzip_setuptools=False,
941 prompt=None, search_dirs=None, never_download=False,
942 no_setuptools=False, no_pip=False, symlink=True):
943 """
944 Creates a new environment in ``home_dir``.
945
946 If ``site_packages`` is true, then the global ``site-packages/``
947 directory will be on the path.
948
949 If ``clear`` is true (default False) then the environment will
950 first be cleared.
951 """
952 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
953
954 py_executable = os.path.abspath(install_python(
955 home_dir, lib_dir, inc_dir, bin_dir,
956 site_packages=site_packages, clear=clear, symlink=symlink))
957
958 install_distutils(home_dir)
959
960 if not no_setuptools:
961 install_sdist('Setuptools', 'setuptools-*.tar.gz', py_executable, search_dirs)
962 if not no_pip:
963 install_sdist('Pip', 'pip-*.tar.gz', py_executable, search_dirs)
964
965 install_activate(home_dir, bin_dir, prompt)
966
967def is_executable_file(fpath):
968 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
969
970def path_locations(home_dir):
971 """Return the path locations for the environment (where libraries are,
972 where scripts go, etc)"""
973 # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
974 # prefix arg is broken: http://bugs.python.org/issue3386
975 if is_win:
976 # Windows has lots of problems with executables with spaces in
977 # the name; this function will remove them (using the ~1
978 # format):
979 mkdir(home_dir)
980 if ' ' in home_dir:
981 import ctypes
982 GetShortPathName = ctypes.windll.kernel32.GetShortPathNameW
983 size = max(len(home_dir)+1, 256)
984 buf = ctypes.create_unicode_buffer(size)
985 try:
986 u = unicode
987 except NameError:
988 u = str
989 ret = GetShortPathName(u(home_dir), buf, size)
990 if not ret:
991 print('Error: the path "%s" has a space in it' % home_dir)
992 print('We could not determine the short pathname for it.')
993 print('Exiting.')
994 sys.exit(3)
995 home_dir = str(buf.value)
996 lib_dir = join(home_dir, 'Lib')
997 inc_dir = join(home_dir, 'Include')
998 bin_dir = join(home_dir, 'Scripts')
999 if is_jython:
1000 lib_dir = join(home_dir, 'Lib')
1001 inc_dir = join(home_dir, 'Include')
1002 bin_dir = join(home_dir, 'bin')
1003 elif is_pypy:
1004 lib_dir = home_dir
1005 inc_dir = join(home_dir, 'include')
1006 bin_dir = join(home_dir, 'bin')
1007 elif not is_win:
1008 lib_dir = join(home_dir, 'lib', py_version)
1009 multiarch_exec = '/usr/bin/multiarch-platform'
1010 if is_executable_file(multiarch_exec):
1011 # In Mageia (2) and Mandriva distros the include dir must be like:
1012 # virtualenv/include/multiarch-x86_64-linux/python2.7
1013 # instead of being virtualenv/include/python2.7
1014 p = subprocess.Popen(multiarch_exec, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
1015 stdout, stderr = p.communicate()
1016 # stdout.strip is needed to remove newline character
1017 inc_dir = join(home_dir, 'include', stdout.strip(), py_version + abiflags)
1018 else:
1019 inc_dir = join(home_dir, 'include', py_version + abiflags)
1020 bin_dir = join(home_dir, 'bin')
1021 return home_dir, lib_dir, inc_dir, bin_dir
1022
1023
1024def change_prefix(filename, dst_prefix):
1025 prefixes = [sys.prefix]
1026
1027 if is_darwin:
1028 prefixes.extend((
1029 os.path.join("/Library/Python", sys.version[:3], "site-packages"),
1030 os.path.join(sys.prefix, "Extras", "lib", "python"),
1031 os.path.join("~", "Library", "Python", sys.version[:3], "site-packages"),
1032 # Python 2.6 no-frameworks
1033 os.path.join("~", ".local", "lib","python", sys.version[:3], "site-packages"),
1034 # System Python 2.7 on OSX Mountain Lion
1035 os.path.join("~", "Library", "Python", sys.version[:3], "lib", "python", "site-packages")))
1036
1037 if hasattr(sys, 'real_prefix'):
1038 prefixes.append(sys.real_prefix)
1039 if hasattr(sys, 'base_prefix'):
1040 prefixes.append(sys.base_prefix)
1041 prefixes = list(map(os.path.expanduser, prefixes))
1042 prefixes = list(map(os.path.abspath, prefixes))
1043 # Check longer prefixes first so we don't split in the middle of a filename
1044 prefixes = sorted(prefixes, key=len, reverse=True)
1045 filename = os.path.abspath(filename)
1046 for src_prefix in prefixes:
1047 if filename.startswith(src_prefix):
1048 _, relpath = filename.split(src_prefix, 1)
1049 if src_prefix != os.sep: # sys.prefix == "/"
1050 assert relpath[0] == os.sep
1051 relpath = relpath[1:]
1052 return join(dst_prefix, relpath)
1053 assert False, "Filename %s does not start with any of these prefixes: %s" % \
1054 (filename, prefixes)
1055
1056def copy_required_modules(dst_prefix, symlink):
1057 import imp
1058 # If we are running under -p, we need to remove the current
1059 # directory from sys.path temporarily here, so that we
1060 # definitely get the modules from the site directory of
1061 # the interpreter we are running under, not the one
1062 # virtualenv.py is installed under (which might lead to py2/py3
1063 # incompatibility issues)
1064 _prev_sys_path = sys.path
1065 if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
1066 sys.path = sys.path[1:]
1067 try:
1068 for modname in REQUIRED_MODULES:
1069 if modname in sys.builtin_module_names:
1070 logger.info("Ignoring built-in bootstrap module: %s" % modname)
1071 continue
1072 try:
1073 f, filename, _ = imp.find_module(modname)
1074 except ImportError:
1075 logger.info("Cannot import bootstrap module: %s" % modname)
1076 else:
1077 if f is not None:
1078 f.close()
1079 # special-case custom readline.so on OS X, but not for pypy:
1080 if modname == 'readline' and sys.platform == 'darwin' and not (
1081 is_pypy or filename.endswith(join('lib-dynload', 'readline.so'))):
1082 dst_filename = join(dst_prefix, 'lib', 'python%s' % sys.version[:3], 'readline.so')
1083 elif modname == 'readline' and sys.platform == 'win32':
1084 # special-case for Windows, where readline is not a
1085 # standard module, though it may have been installed in
1086 # site-packages by a third-party package
1087 pass
1088 else:
1089 dst_filename = change_prefix(filename, dst_prefix)
1090 copyfile(filename, dst_filename, symlink)
1091 if filename.endswith('.pyc'):
1092 pyfile = filename[:-1]
1093 if os.path.exists(pyfile):
1094 copyfile(pyfile, dst_filename[:-1], symlink)
1095 finally:
1096 sys.path = _prev_sys_path
1097
1098
1099def subst_path(prefix_path, prefix, home_dir):
1100 prefix_path = os.path.normpath(prefix_path)
1101 prefix = os.path.normpath(prefix)
1102 home_dir = os.path.normpath(home_dir)
1103 if not prefix_path.startswith(prefix):
1104 logger.warn('Path not in prefix %r %r', prefix_path, prefix)
1105 return
1106 return prefix_path.replace(prefix, home_dir, 1)
1107
1108
1109def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, symlink=True):
1110 """Install just the base environment, no distutils patches etc"""
1111 if sys.executable.startswith(bin_dir):
1112 print('Please use the *system* python to run this script')
1113 return
1114
1115 if clear:
1116 rmtree(lib_dir)
1117 ## FIXME: why not delete it?
1118 ## Maybe it should delete everything with #!/path/to/venv/python in it
1119 logger.notify('Not deleting %s', bin_dir)
1120
1121 if hasattr(sys, 'real_prefix'):
1122 logger.notify('Using real prefix %r' % sys.real_prefix)
1123 prefix = sys.real_prefix
1124 elif hasattr(sys, 'base_prefix'):
1125 logger.notify('Using base prefix %r' % sys.base_prefix)
1126 prefix = sys.base_prefix
1127 else:
1128 prefix = sys.prefix
1129 mkdir(lib_dir)
1130 fix_lib64(lib_dir, symlink)
1131 stdlib_dirs = [os.path.dirname(os.__file__)]
1132 if is_win:
1133 stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
1134 elif is_darwin:
1135 stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
1136 if hasattr(os, 'symlink'):
1137 logger.info('Symlinking Python bootstrap modules')
1138 else:
1139 logger.info('Copying Python bootstrap modules')
1140 logger.indent += 2
1141 try:
1142 # copy required files...
1143 for stdlib_dir in stdlib_dirs:
1144 if not os.path.isdir(stdlib_dir):
1145 continue
1146 for fn in os.listdir(stdlib_dir):
1147 bn = os.path.splitext(fn)[0]
1148 if fn != 'site-packages' and bn in REQUIRED_FILES:
1149 copyfile(join(stdlib_dir, fn), join(lib_dir, fn), symlink)
1150 # ...and modules
1151 copy_required_modules(home_dir, symlink)
1152 finally:
1153 logger.indent -= 2
1154 mkdir(join(lib_dir, 'site-packages'))
1155 import site
1156 site_filename = site.__file__
1157 if site_filename.endswith('.pyc'):
1158 site_filename = site_filename[:-1]
1159 elif site_filename.endswith('$py.class'):
1160 site_filename = site_filename.replace('$py.class', '.py')
1161 site_filename_dst = change_prefix(site_filename, home_dir)
1162 site_dir = os.path.dirname(site_filename_dst)
1163 writefile(site_filename_dst, SITE_PY)
1164 writefile(join(site_dir, 'orig-prefix.txt'), prefix)
1165 site_packages_filename = join(site_dir, 'no-global-site-packages.txt')
1166 if not site_packages:
1167 writefile(site_packages_filename, '')
1168
1169 if is_pypy or is_win:
1170 stdinc_dir = join(prefix, 'include')
1171 else:
1172 stdinc_dir = join(prefix, 'include', py_version + abiflags)
1173 if os.path.exists(stdinc_dir):
1174 copyfile(stdinc_dir, inc_dir, symlink)
1175 else:
1176 logger.debug('No include dir %s' % stdinc_dir)
1177
1178 platinc_dir = distutils.sysconfig.get_python_inc(plat_specific=1)
1179 if platinc_dir != stdinc_dir:
1180 platinc_dest = distutils.sysconfig.get_python_inc(
1181 plat_specific=1, prefix=home_dir)
1182 if platinc_dir == platinc_dest:
1183 # Do platinc_dest manually due to a CPython bug;
1184 # not http://bugs.python.org/issue3386 but a close cousin
1185 platinc_dest = subst_path(platinc_dir, prefix, home_dir)
1186 if platinc_dest:
1187 # PyPy's stdinc_dir and prefix are relative to the original binary
1188 # (traversing virtualenvs), whereas the platinc_dir is relative to
1189 # the inner virtualenv and ignores the prefix argument.
1190 # This seems more evolved than designed.
1191 copyfile(platinc_dir, platinc_dest, symlink)
1192
1193 # pypy never uses exec_prefix, just ignore it
1194 if sys.exec_prefix != prefix and not is_pypy:
1195 if is_win:
1196 exec_dir = join(sys.exec_prefix, 'lib')
1197 elif is_jython:
1198 exec_dir = join(sys.exec_prefix, 'Lib')
1199 else:
1200 exec_dir = join(sys.exec_prefix, 'lib', py_version)
1201 for fn in os.listdir(exec_dir):
1202 copyfile(join(exec_dir, fn), join(lib_dir, fn), symlink)
1203
1204 if is_jython:
1205 # Jython has either jython-dev.jar and javalib/ dir, or just
1206 # jython.jar
1207 for name in 'jython-dev.jar', 'javalib', 'jython.jar':
1208 src = join(prefix, name)
1209 if os.path.exists(src):
1210 copyfile(src, join(home_dir, name), symlink)
1211 # XXX: registry should always exist after Jython 2.5rc1
1212 src = join(prefix, 'registry')
1213 if os.path.exists(src):
1214 copyfile(src, join(home_dir, 'registry'), symlink=False)
1215 copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
1216 symlink=False)
1217
1218 mkdir(bin_dir)
1219 py_executable = join(bin_dir, os.path.basename(sys.executable))
1220 if 'Python.framework' in prefix:
1221 # OS X framework builds cause validation to break
1222 # https://github.com/pypa/virtualenv/issues/322
1223 if os.environ.get('__PYVENV_LAUNCHER__'):
1224 os.unsetenv('__PYVENV_LAUNCHER__')
1225 if re.search(r'/Python(?:-32|-64)*$', py_executable):
1226 # The name of the python executable is not quite what
1227 # we want, rename it.
1228 py_executable = os.path.join(
1229 os.path.dirname(py_executable), 'python')
1230
1231 logger.notify('New %s executable in %s', expected_exe, py_executable)
1232 pcbuild_dir = os.path.dirname(sys.executable)
1233 pyd_pth = os.path.join(lib_dir, 'site-packages', 'virtualenv_builddir_pyd.pth')
1234 if is_win and os.path.exists(os.path.join(pcbuild_dir, 'build.bat')):
1235 logger.notify('Detected python running from build directory %s', pcbuild_dir)
1236 logger.notify('Writing .pth file linking to build directory for *.pyd files')
1237 writefile(pyd_pth, pcbuild_dir)
1238 else:
1239 pcbuild_dir = None
1240 if os.path.exists(pyd_pth):
1241 logger.info('Deleting %s (not Windows env or not build directory python)' % pyd_pth)
1242 os.unlink(pyd_pth)
1243
1244 if sys.executable != py_executable:
1245 ## FIXME: could I just hard link?
1246 executable = sys.executable
1247 shutil.copyfile(executable, py_executable)
1248 make_exe(py_executable)
1249 if is_win or is_cygwin:
1250 pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
1251 if os.path.exists(pythonw):
1252 logger.info('Also created pythonw.exe')
1253 shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
1254 python_d = os.path.join(os.path.dirname(sys.executable), 'python_d.exe')
1255 python_d_dest = os.path.join(os.path.dirname(py_executable), 'python_d.exe')
1256 if os.path.exists(python_d):
1257 logger.info('Also created python_d.exe')
1258 shutil.copyfile(python_d, python_d_dest)
1259 elif os.path.exists(python_d_dest):
1260 logger.info('Removed python_d.exe as it is no longer at the source')
1261 os.unlink(python_d_dest)
1262 # we need to copy the DLL to enforce that windows will load the correct one.
1263 # may not exist if we are cygwin.
1264 py_executable_dll = 'python%s%s.dll' % (
1265 sys.version_info[0], sys.version_info[1])
1266 py_executable_dll_d = 'python%s%s_d.dll' % (
1267 sys.version_info[0], sys.version_info[1])
1268 pythondll = os.path.join(os.path.dirname(sys.executable), py_executable_dll)
1269 pythondll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d)
1270 pythondll_d_dest = os.path.join(os.path.dirname(py_executable), py_executable_dll_d)
1271 if os.path.exists(pythondll):
1272 logger.info('Also created %s' % py_executable_dll)
1273 shutil.copyfile(pythondll, os.path.join(os.path.dirname(py_executable), py_executable_dll))
1274 if os.path.exists(pythondll_d):
1275 logger.info('Also created %s' % py_executable_dll_d)
1276 shutil.copyfile(pythondll_d, pythondll_d_dest)
1277 elif os.path.exists(pythondll_d_dest):
1278 logger.info('Removed %s as the source does not exist' % pythondll_d_dest)
1279 os.unlink(pythondll_d_dest)
1280 if is_pypy:
1281 # make a symlink python --> pypy-c
1282 python_executable = os.path.join(os.path.dirname(py_executable), 'python')
1283 if sys.platform in ('win32', 'cygwin'):
1284 python_executable += '.exe'
1285 logger.info('Also created executable %s' % python_executable)
1286 copyfile(py_executable, python_executable, symlink)
1287
1288 if is_win:
1289 for name in 'libexpat.dll', 'libpypy.dll', 'libpypy-c.dll', 'libeay32.dll', 'ssleay32.dll', 'sqlite.dll':
1290 src = join(prefix, name)
1291 if os.path.exists(src):
1292 copyfile(src, join(bin_dir, name), symlink)
1293
1294 if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
1295 secondary_exe = os.path.join(os.path.dirname(py_executable),
1296 expected_exe)
1297 py_executable_ext = os.path.splitext(py_executable)[1]
1298 if py_executable_ext.lower() == '.exe':
1299 # python2.4 gives an extension of '.4' :P
1300 secondary_exe += py_executable_ext
1301 if os.path.exists(secondary_exe):
1302 logger.warn('Not overwriting existing %s script %s (you must use %s)'
1303 % (expected_exe, secondary_exe, py_executable))
1304 else:
1305 logger.notify('Also creating executable in %s' % secondary_exe)
1306 shutil.copyfile(sys.executable, secondary_exe)
1307 make_exe(secondary_exe)
1308
1309 if '.framework' in prefix:
1310 if 'Python.framework' in prefix:
1311 logger.debug('MacOSX Python framework detected')
1312 # Make sure we use the the embedded interpreter inside
1313 # the framework, even if sys.executable points to
1314 # the stub executable in ${sys.prefix}/bin
1315 # See http://groups.google.com/group/python-virtualenv/
1316 # browse_thread/thread/17cab2f85da75951
1317 original_python = os.path.join(
1318 prefix, 'Resources/Python.app/Contents/MacOS/Python')
1319 if 'EPD' in prefix:
1320 logger.debug('EPD framework detected')
1321 original_python = os.path.join(prefix, 'bin/python')
1322 shutil.copy(original_python, py_executable)
1323
1324 # Copy the framework's dylib into the virtual
1325 # environment
1326 virtual_lib = os.path.join(home_dir, '.Python')
1327
1328 if os.path.exists(virtual_lib):
1329 os.unlink(virtual_lib)
1330 copyfile(
1331 os.path.join(prefix, 'Python'),
1332 virtual_lib,
1333 symlink)
1334
1335 # And then change the install_name of the copied python executable
1336 try:
1337 mach_o_change(py_executable,
1338 os.path.join(prefix, 'Python'),
1339 '@executable_path/../.Python')
1340 except:
1341 e = sys.exc_info()[1]
1342 logger.warn("Could not call mach_o_change: %s. "
1343 "Trying to call install_name_tool instead." % e)
1344 try:
1345 call_subprocess(
1346 ["install_name_tool", "-change",
1347 os.path.join(prefix, 'Python'),
1348 '@executable_path/../.Python',
1349 py_executable])
1350 except:
1351 logger.fatal("Could not call install_name_tool -- you must "
1352 "have Apple's development tools installed")
1353 raise
1354
1355 if not is_win:
1356 # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist
1357 py_exe_version_major = 'python%s' % sys.version_info[0]
1358 py_exe_version_major_minor = 'python%s.%s' % (
1359 sys.version_info[0], sys.version_info[1])
1360 py_exe_no_version = 'python'
1361 required_symlinks = [ py_exe_no_version, py_exe_version_major,
1362 py_exe_version_major_minor ]
1363
1364 py_executable_base = os.path.basename(py_executable)
1365
1366 if py_executable_base in required_symlinks:
1367 # Don't try to symlink to yourself.
1368 required_symlinks.remove(py_executable_base)
1369
1370 for pth in required_symlinks:
1371 full_pth = join(bin_dir, pth)
1372 if os.path.exists(full_pth):
1373 os.unlink(full_pth)
1374 if symlink:
1375 os.symlink(py_executable_base, full_pth)
1376 else:
1377 shutil.copyfile(py_executable_base, full_pth)
1378
1379 if is_win and ' ' in py_executable:
1380 # There's a bug with subprocess on Windows when using a first
1381 # argument that has a space in it. Instead we have to quote
1382 # the value:
1383 py_executable = '"%s"' % py_executable
1384 # NOTE: keep this check as one line, cmd.exe doesn't cope with line breaks
1385 cmd = [py_executable, '-c', 'import sys;out=sys.stdout;'
1386 'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))']
1387 logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
1388 try:
1389 proc = subprocess.Popen(cmd,
1390 stdout=subprocess.PIPE)
1391 proc_stdout, proc_stderr = proc.communicate()
1392 except OSError:
1393 e = sys.exc_info()[1]
1394 if e.errno == errno.EACCES:
1395 logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e))
1396 sys.exit(100)
1397 else:
1398 raise e
1399
1400 proc_stdout = proc_stdout.strip().decode("utf-8")
1401 proc_stdout = os.path.normcase(os.path.abspath(proc_stdout))
1402 norm_home_dir = os.path.normcase(os.path.abspath(home_dir))
1403 if hasattr(norm_home_dir, 'decode'):
1404 norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding())
1405 if proc_stdout != norm_home_dir:
1406 logger.fatal(
1407 'ERROR: The executable %s is not functioning' % py_executable)
1408 logger.fatal(
1409 'ERROR: It thinks sys.prefix is %r (should be %r)'
1410 % (proc_stdout, norm_home_dir))
1411 logger.fatal(
1412 'ERROR: virtualenv is not compatible with this system or executable')
1413 if is_win:
1414 logger.fatal(
1415 'Note: some Windows users have reported this error when they '
1416 'installed Python for "Only this user" or have multiple '
1417 'versions of Python installed. Copying the appropriate '
1418 'PythonXX.dll to the virtualenv Scripts/ directory may fix '
1419 'this problem.')
1420 sys.exit(100)
1421 else:
1422 logger.info('Got sys.prefix result: %r' % proc_stdout)
1423
1424 pydistutils = os.path.expanduser('~/.pydistutils.cfg')
1425 if os.path.exists(pydistutils):
1426 logger.notify('Please make sure you remove any previous custom paths from '
1427 'your %s file.' % pydistutils)
1428 ## FIXME: really this should be calculated earlier
1429
1430 fix_local_scheme(home_dir, symlink)
1431
1432 if site_packages:
1433 if os.path.exists(site_packages_filename):
1434 logger.info('Deleting %s' % site_packages_filename)
1435 os.unlink(site_packages_filename)
1436
1437 return py_executable
1438
1439
1440def install_activate(home_dir, bin_dir, prompt=None):
1441 home_dir = os.path.abspath(home_dir)
1442 if is_win or is_jython and os._name == 'nt':
1443 files = {
1444 'activate.bat': ACTIVATE_BAT,
1445 'deactivate.bat': DEACTIVATE_BAT,
1446 'activate.ps1': ACTIVATE_PS,
1447 }
1448
1449 # MSYS needs paths of the form /c/path/to/file
1450 drive, tail = os.path.splitdrive(home_dir.replace(os.sep, '/'))
1451 home_dir_msys = (drive and "/%s%s" or "%s%s") % (drive[:1], tail)
1452
1453 # Run-time conditional enables (basic) Cygwin compatibility
1454 home_dir_sh = ("""$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '%s'; else echo '%s'; fi;)""" %
1455 (home_dir, home_dir_msys))
1456 files['activate'] = ACTIVATE_SH.replace('__VIRTUAL_ENV__', home_dir_sh)
1457
1458 else:
1459 files = {'activate': ACTIVATE_SH}
1460
1461 # suppling activate.fish in addition to, not instead of, the
1462 # bash script support.
1463 files['activate.fish'] = ACTIVATE_FISH
1464
1465 # same for csh/tcsh support...
1466 files['activate.csh'] = ACTIVATE_CSH
1467
1468 files['activate_this.py'] = ACTIVATE_THIS
1469 if hasattr(home_dir, 'decode'):
1470 home_dir = home_dir.decode(sys.getfilesystemencoding())
1471 vname = os.path.basename(home_dir)
1472 for name, content in files.items():
1473 content = content.replace('__VIRTUAL_PROMPT__', prompt or '')
1474 content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)
1475 content = content.replace('__VIRTUAL_ENV__', home_dir)
1476 content = content.replace('__VIRTUAL_NAME__', vname)
1477 content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
1478 writefile(os.path.join(bin_dir, name), content)
1479
1480def install_distutils(home_dir):
1481 distutils_path = change_prefix(distutils.__path__[0], home_dir)
1482 mkdir(distutils_path)
1483 ## FIXME: maybe this prefix setting should only be put in place if
1484 ## there's a local distutils.cfg with a prefix setting?
1485 home_dir = os.path.abspath(home_dir)
1486 ## FIXME: this is breaking things, removing for now:
1487 #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
1488 writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
1489 writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
1490
1491def fix_local_scheme(home_dir, symlink=True):
1492 """
1493 Platforms that use the "posix_local" install scheme (like Ubuntu with
1494 Python 2.7) need to be given an additional "local" location, sigh.
1495 """
1496 try:
1497 import sysconfig
1498 except ImportError:
1499 pass
1500 else:
1501 if sysconfig._get_default_scheme() == 'posix_local':
1502 local_path = os.path.join(home_dir, 'local')
1503 if not os.path.exists(local_path):
1504 os.mkdir(local_path)
1505 for subdir_name in os.listdir(home_dir):
1506 if subdir_name == 'local':
1507 continue
1508 cp_or_ln = (os.symlink if symlink else copyfile)
1509 cp_or_ln(os.path.abspath(os.path.join(home_dir, subdir_name)), \
1510 os.path.join(local_path, subdir_name))
1511
1512def fix_lib64(lib_dir, symlink=True):
1513 """
1514 Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
1515 instead of lib/pythonX.Y. If this is such a platform we'll just create a
1516 symlink so lib64 points to lib
1517 """
1518 if [p for p in distutils.sysconfig.get_config_vars().values()
1519 if isinstance(p, basestring) and 'lib64' in p]:
1520 # PyPy's library path scheme is not affected by this.
1521 # Return early or we will die on the following assert.
1522 if is_pypy:
1523 logger.debug('PyPy detected, skipping lib64 symlinking')
1524 return
1525
1526 logger.debug('This system uses lib64; symlinking lib64 to lib')
1527
1528 assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
1529 "Unexpected python lib dir: %r" % lib_dir)
1530 lib_parent = os.path.dirname(lib_dir)
1531 top_level = os.path.dirname(lib_parent)
1532 lib_dir = os.path.join(top_level, 'lib')
1533 lib64_link = os.path.join(top_level, 'lib64')
1534 assert os.path.basename(lib_parent) == 'lib', (
1535 "Unexpected parent dir: %r" % lib_parent)
1536 if os.path.lexists(lib64_link):
1537 return
1538 cp_or_ln = (os.symlink if symlink else copyfile)
1539 cp_or_ln('lib', lib64_link)
1540
1541def resolve_interpreter(exe):
1542 """
1543 If the executable given isn't an absolute path, search $PATH for the interpreter
1544 """
1545 # If the "executable" is a version number, get the installed executable for
1546 # that version
1547 python_versions = get_installed_pythons()
1548 if exe in python_versions:
1549 exe = python_versions[exe]
1550
1551 if os.path.abspath(exe) != exe:
1552 paths = os.environ.get('PATH', '').split(os.pathsep)
1553 for path in paths:
1554 if os.path.exists(os.path.join(path, exe)):
1555 exe = os.path.join(path, exe)
1556 break
1557 if not os.path.exists(exe):
1558 logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
1559 raise SystemExit(3)
1560 if not is_executable(exe):
1561 logger.fatal('The executable %s (from --python=%s) is not executable' % (exe, exe))
1562 raise SystemExit(3)
1563 return exe
1564
1565def is_executable(exe):
1566 """Checks a file is executable"""
1567 return os.access(exe, os.X_OK)
1568
1569############################################################
1570## Relocating the environment:
1571
1572def make_environment_relocatable(home_dir):
1573 """
1574 Makes the already-existing environment use relative paths, and takes out
1575 the #!-based environment selection in scripts.
1576 """
1577 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
1578 activate_this = os.path.join(bin_dir, 'activate_this.py')
1579 if not os.path.exists(activate_this):
1580 logger.fatal(
1581 'The environment doesn\'t have a file %s -- please re-run virtualenv '
1582 'on this environment to update it' % activate_this)
1583 fixup_scripts(home_dir, bin_dir)
1584 fixup_pth_and_egg_link(home_dir)
1585 ## FIXME: need to fix up distutils.cfg
1586
1587OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
1588 'activate', 'activate.bat', 'activate_this.py']
1589
1590def fixup_scripts(home_dir, bin_dir):
1591 if is_win:
1592 new_shebang_args = (
1593 '%s /c' % os.path.normcase(os.environ.get('COMSPEC', 'cmd.exe')),
1594 '', '.exe')
1595 else:
1596 new_shebang_args = ('/usr/bin/env', sys.version[:3], '')
1597
1598 # This is what we expect at the top of scripts:
1599 shebang = '#!%s' % os.path.normcase(os.path.join(
1600 os.path.abspath(bin_dir), 'python%s' % new_shebang_args[2]))
1601 # This is what we'll put:
1602 new_shebang = '#!%s python%s%s' % new_shebang_args
1603
1604 for filename in os.listdir(bin_dir):
1605 filename = os.path.join(bin_dir, filename)
1606 if not os.path.isfile(filename):
1607 # ignore subdirs, e.g. .svn ones.
1608 continue
1609 f = open(filename, 'rb')
1610 try:
1611 try:
1612 lines = f.read().decode('utf-8').splitlines()
1613 except UnicodeDecodeError:
1614 # This is probably a binary program instead
1615 # of a script, so just ignore it.
1616 continue
1617 finally:
1618 f.close()
1619 if not lines:
1620 logger.warn('Script %s is an empty file' % filename)
1621 continue
1622
1623 old_shebang = lines[0].strip()
1624 old_shebang = old_shebang[0:2] + os.path.normcase(old_shebang[2:])
1625
1626 if not old_shebang.startswith(shebang):
1627 if os.path.basename(filename) in OK_ABS_SCRIPTS:
1628 logger.debug('Cannot make script %s relative' % filename)
1629 elif lines[0].strip() == new_shebang:
1630 logger.info('Script %s has already been made relative' % filename)
1631 else:
1632 logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
1633 % (filename, shebang))
1634 continue
1635 logger.notify('Making script %s relative' % filename)
1636 script = relative_script([new_shebang] + lines[1:])
1637 f = open(filename, 'wb')
1638 f.write('\n'.join(script).encode('utf-8'))
1639 f.close()
1640
1641def relative_script(lines):
1642 "Return a script that'll work in a relocatable environment."
1643 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"
1644 # Find the last future statement in the script. If we insert the activation
1645 # line before a future statement, Python will raise a SyntaxError.
1646 activate_at = None
1647 for idx, line in reversed(list(enumerate(lines))):
1648 if line.split()[:3] == ['from', '__future__', 'import']:
1649 activate_at = idx + 1
1650 break
1651 if activate_at is None:
1652 # Activate after the shebang.
1653 activate_at = 1
1654 return lines[:activate_at] + ['', activate, ''] + lines[activate_at:]
1655
1656def fixup_pth_and_egg_link(home_dir, sys_path=None):
1657 """Makes .pth and .egg-link files use relative paths"""
1658 home_dir = os.path.normcase(os.path.abspath(home_dir))
1659 if sys_path is None:
1660 sys_path = sys.path
1661 for path in sys_path:
1662 if not path:
1663 path = '.'
1664 if not os.path.isdir(path):
1665 continue
1666 path = os.path.normcase(os.path.abspath(path))
1667 if not path.startswith(home_dir):
1668 logger.debug('Skipping system (non-environment) directory %s' % path)
1669 continue
1670 for filename in os.listdir(path):
1671 filename = os.path.join(path, filename)
1672 if filename.endswith('.pth'):
1673 if not os.access(filename, os.W_OK):
1674 logger.warn('Cannot write .pth file %s, skipping' % filename)
1675 else:
1676 fixup_pth_file(filename)
1677 if filename.endswith('.egg-link'):
1678 if not os.access(filename, os.W_OK):
1679 logger.warn('Cannot write .egg-link file %s, skipping' % filename)
1680 else:
1681 fixup_egg_link(filename)
1682
1683def fixup_pth_file(filename):
1684 lines = []
1685 prev_lines = []
1686 f = open(filename)
1687 prev_lines = f.readlines()
1688 f.close()
1689 for line in prev_lines:
1690 line = line.strip()
1691 if (not line or line.startswith('#') or line.startswith('import ')
1692 or os.path.abspath(line) != line):
1693 lines.append(line)
1694 else:
1695 new_value = make_relative_path(filename, line)
1696 if line != new_value:
1697 logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
1698 lines.append(new_value)
1699 if lines == prev_lines:
1700 logger.info('No changes to .pth file %s' % filename)
1701 return
1702 logger.notify('Making paths in .pth file %s relative' % filename)
1703 f = open(filename, 'w')
1704 f.write('\n'.join(lines) + '\n')
1705 f.close()
1706
1707def fixup_egg_link(filename):
1708 f = open(filename)
1709 link = f.readline().strip()
1710 f.close()
1711 if os.path.abspath(link) != link:
1712 logger.debug('Link in %s already relative' % filename)
1713 return
1714 new_link = make_relative_path(filename, link)
1715 logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
1716 f = open(filename, 'w')
1717 f.write(new_link)
1718 f.close()
1719
1720def make_relative_path(source, dest, dest_is_directory=True):
1721 """
1722 Make a filename relative, where the filename is dest, and it is
1723 being referred to from the filename source.
1724
1725 >>> make_relative_path('/usr/share/something/a-file.pth',
1726 ... '/usr/share/another-place/src/Directory')
1727 '../another-place/src/Directory'
1728 >>> make_relative_path('/usr/share/something/a-file.pth',
1729 ... '/home/user/src/Directory')
1730 '../../../home/user/src/Directory'
1731 >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
1732 './'
1733 """
1734 source = os.path.dirname(source)
1735 if not dest_is_directory:
1736 dest_filename = os.path.basename(dest)
1737 dest = os.path.dirname(dest)
1738 dest = os.path.normpath(os.path.abspath(dest))
1739 source = os.path.normpath(os.path.abspath(source))
1740 dest_parts = dest.strip(os.path.sep).split(os.path.sep)
1741 source_parts = source.strip(os.path.sep).split(os.path.sep)
1742 while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
1743 dest_parts.pop(0)
1744 source_parts.pop(0)
1745 full_parts = ['..']*len(source_parts) + dest_parts
1746 if not dest_is_directory:
1747 full_parts.append(dest_filename)
1748 if not full_parts:
1749 # Special case for the current directory (otherwise it'd be '')
1750 return './'
1751 return os.path.sep.join(full_parts)
1752
1753
1754
1755############################################################
1756## Bootstrap script creation:
1757
1758def create_bootstrap_script(extra_text, python_version=''):
1759 """
1760 Creates a bootstrap script, which is like this script but with
1761 extend_parser, adjust_options, and after_install hooks.
1762
1763 This returns a string that (written to disk of course) can be used
1764 as a bootstrap script with your own customizations. The script
1765 will be the standard virtualenv.py script, with your extra text
1766 added (your extra text should be Python code).
1767
1768 If you include these functions, they will be called:
1769
1770 ``extend_parser(optparse_parser)``:
1771 You can add or remove options from the parser here.
1772
1773 ``adjust_options(options, args)``:
1774 You can change options here, or change the args (if you accept
1775 different kinds of arguments, be sure you modify ``args`` so it is
1776 only ``[DEST_DIR]``).
1777
1778 ``after_install(options, home_dir)``:
1779
1780 After everything is installed, this function is called. This
1781 is probably the function you are most likely to use. An
1782 example would be::
1783
1784 def after_install(options, home_dir):
1785 subprocess.call([join(home_dir, 'bin', 'easy_install'),
1786 'MyPackage'])
1787 subprocess.call([join(home_dir, 'bin', 'my-package-script'),
1788 'setup', home_dir])
1789
1790 This example immediately installs a package, and runs a setup
1791 script from that package.
1792
1793 If you provide something like ``python_version='2.5'`` then the
1794 script will start with ``#!/usr/bin/env python2.5`` instead of
1795 ``#!/usr/bin/env python``. You can use this when the script must
1796 be run with a particular Python version.
1797 """
1798 filename = __file__
1799 if filename.endswith('.pyc'):
1800 filename = filename[:-1]
1801 f = codecs.open(filename, 'r', encoding='utf-8')
1802 content = f.read()
1803 f.close()
1804 py_exe = 'python%s' % python_version
1805 content = (('#!/usr/bin/env %s\n' % py_exe)
1806 + '## WARNING: This file is generated\n'
1807 + content)
1808 return content.replace('##EXT' 'END##', extra_text)
1809
1810##EXTEND##
1811
1812def convert(s):
1813 b = base64.b64decode(s.encode('ascii'))
1814 return zlib.decompress(b).decode('utf-8')
1815
1816##file site.py
1817SITE_PY = convert("""
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
1958abV46zZtMMiZnWgPwBqF4P8ACHXrHw==
1959""")
1960
1961##file activate.sh
1962ACTIVATE_SH = convert("""
1963eJytVVFvokAQfudXTLEPtTlLeo9tvMSmJpq02hSvl7u2wRUG2QR2DSxSe7n/frOACEVNLlceRHa+
1964nfl25pvZDswCnoDPQ4QoTRQsENIEPci4CsBMZBq7CAsuLOYqvmYKTTj3YxnBgiXBudGBjUzBZUJI
1965BXEqgCvweIyuCjeG4eF2F5x14bcB9KQiQQWrjSddI1/oQIx6SYYeoFjzWIoIhYI1izlbhJjkKO7D
1966M/QEmKfO9O7WeRo/zr4P7pyHwWxkwitcgwpQ5Ej96OX+PmiFwLeVjFUOrNYKaq1Nud3nR2n8nI2m
1967k9H0friPTGVsUdptaxGrTEfpNVFEskxpXtUkkCkl1UNF9cgLBkx48J4EXyALuBtAwNYIjF5kcmUU
1968abMKmMq1ULoiRbgsDEkTSsKSGFCJ6Z8vY/2xYiSacmtyAfCDdCNTVZoVF8vSTQOoEwSnOrngBkws
1969MYGMBMg8/bMBLSYKS7pYEXP0PqT+ZmBT0Xuy+Pplj5yn4aM9nk72JD8/Wi+Gr98sD9eWSMOwkapD
1970BbUv91XSvmyVkICt2tmXR4tWmrcUCsjWOpw87YidEC8i0gdTSOFhouJUNxR+4NYBG0MftoCTD9F7
19712rTtxG3oPwY1b2HncYwhrlmj6Wq924xtGDWqfdNxap+OYxplEurnMVo9RWks+rH8qKEtx7kZT5zJ
19724H7oOFclrN6uFe+d+nW2aIUsSgs/42EIPuOhXq+jEo3S6tX6w2ilNkDnIpHCWdEQhFgwj9pkk7FN
1973l/y5eQvRSIQ5+TrL05lewxWpt/Lbhes5cJF3mLET1MGhcKCF+40tNWnUulxrpojwDo2sObdje3Bz
1974N3QeHqf3D7OjEXMVV8LN3ZlvuzoWHqiUcNKHtwNd0IbvPGKYYM31nPKCgkUILw3KL+Y8l7aO1ArS
1975Ad37nIU0fCj5NE5gQCuC5sOSu+UdI2NeXg/lFkQIlFpdWVaWZRfvqGiirC9o6liJ9FXGYrSY9mI1
1976D/Ncozgn13vJvsznr7DnkJWXsyMH7e42ljdJ+aqNDF1bFnKWFLdj31xtaJYK6EXFgqmV/ymD/ROG
1977+n8O9H8f5vsGOWXsL1+1k3g=
1978""")
1979
1980##file activate.fish
1981ACTIVATE_FISH = convert("""
1982eJyVVWFv2jAQ/c6vuBoqQVWC9nVSNVGVCaS2VC2rNLWVZZILWAs2s52wVvvxsyEJDrjbmgpK7PP5
19833bt3d22YLbmGlGcIq1wbmCPkGhPYcLMEEsGciwGLDS+YwSjlekngLFVyBe73GXSXxqw/DwbuTS8x
1984yyKpFr1WG15lDjETQhpQuQBuIOEKY5O9tlppLqxHKSDByjVAPwEy+mXtCq5MzjIUBTCRgEKTKwFG
1985gpBqxTLYXgN2myspVigMaYF92tZSowGZJf4mFExxNs9Qb614CgZtmH0BpEOn11f0cXI/+za8pnfD
19862ZjA1sg9zlV/8QvcMhxbNu0QwgYokn/d+n02nt6Opzcjcnx1vXcIoN74O4ymWQXmHURfJw9jenc/
1987vbmb0enj6P5+cuVhqlKm3S0u2XRtRbA2QQAhV7VhBF0rsgUX9Ur1rBUXJgVSy8O751k8mzY5OrKH
1988RW3eaQhYGTr8hrXO59ALhxQ83mCsDLAid3T72CCSdJhaFE+fXgicXAARUiR2WeVO37gH3oYHzFKo
19899k7CaPZ1UeNwH1tWuXA4uFKYYcEa8vaKqXl7q1UpygMPhFLvlVKyNzsSM3S2km7UBOl4xweUXk5u
19906e3wZmQ9leY1XE/Ili670tr9g/5POBBpGIJXCCF79L1siarl/dbESa8mD8PL61GpzqpzuMS7tqeB
19911YkALrRBloBMbR9yLcVx7frQAgUqR7NZIuzkEu110gbNit1enNs82Rx5utq7Z3prU78HFRgulqNC
1992OTwbqJa9vkJFclQgZSjbKeBgSsUtCtt9D8OwAbIVJuewQdfvQRaoFE9wd1TmCuRG7OgJ1bVXGHc7
1993z5WDL/WW36v2oi37CyVBak61+yPBA9C1qqGxzKQqZ0oPuocU9hpud0PIp8sDHkXR1HKkNlzjuUWA
1994a0enFUyzOWZA4yXGP+ZMI3Tdt2OuqU/SO4q64526cPE0A7ZyW2PMbWZiZ5HamIZ2RcCKLXhcDl2b
1995vXL+eccQoRzem80mekPDEiyiWK4GWqZmwxQOmPM0eIfgp1P9cqrBsewR2p/DPMtt+pfcYM+Ls2uh
1996hALufTAdmGl8B1H3VPd2af8fQAc4PgqjlIBL9cGQqNpXaAwe3LrtVn8AkZTUxg==
1997""")
1998
1999##file activate.csh
2000ACTIVATE_CSH = convert("""
2001eJx9VG1P2zAQ/u5fcYQKNgTNPtN1WxlIQ4KCUEGaxuQ6yYVYSuzKdhqVX7+zk3bpy5YPUXL3PPfc
2002ne98DLNCWshliVDV1kGCUFvMoJGugMjq2qQIiVSxSJ1cCofD1BYRnOVGV0CfZ0N2DD91DalQSjsw
2003tQLpIJMGU1euvPe7QeJlkKzgWixlhnAt4aoUVsLnLBiy5NtbJWQ5THX1ZciYKKWwkOFaE04dUm6D
2004r/zh7pq/3D7Nnid3/HEy+wFHY/gEJydg0aFaQrBFgz1c5DG1IhTs+UZgsBC2GMFBlaeH+8dZXwcW
2005VPvCjXdlAvCfQsE7al0+07XjZvrSCUevR5dnkVeKlFYZmUztG4BdzL2u9KyLVabTU0bdfg7a0hgs
2006cSmUg6UwUiQl2iHrcbcVGNvPCiLOe7+cRwG13z9qRGgx2z6DHjfm/Op2yqeT+xvOLzs0PTKHDz2V
2007tkckFHoQfQRXoGJAj9el0FyJCmEMhzgMS4sB7KPOE2ExoLcSieYwDvR+cP8cg11gKkVJc2wRcm1g
2008QhYFlXiTaTfO2ki0fQoiFM4tLuO4aZrhOzqR4dIPcWx17hphMBY+Srwh7RTyN83XOWkcSPh1Pg/k
2009TXX/jbJTbMtUmcxZ+/bbqOsy82suFQg/BhdSOTRhMNBHlUarCpU7JzBhmkKmRejKOQzayQe6MWoa
2010n1wqWmuh6LZAaHxcdeqIlVLhIBJdO9/kbl0It2oEXQj+eGjJOuvOIR/YGRqvFhttUB2XTvLXYN2H
201137CBdbW2W7j2r2+VsCn0doVWcFG1/4y1VwBjfwAyoZhD
2012""")
2013
2014##file activate.bat
2015ACTIVATE_BAT = convert("""
2016eJx9UdEKgjAUfW6wfxjiIH+hEDKUFHSKLCMI7kNOEkIf9P9pTJ3OLJ/03HPPPed4Es9XS9qqwqgT
2017PbGKKOdXL4aAFS7A4gvAwgijuiKlqOpGlATS2NeMLE+TjJM9RkQ+SmqAXLrBo1LLIeLdiWlD6jZt
2018r7VNubWkndkXaxg5GO3UaOOKS6drO3luDDiO5my3iA0YAKGzPRV1ack8cOdhysI0CYzIPzjSiH5X
20190QcvC8Lfaj0emsVKYF2rhL5L3fCkVjV76kShi59NHwDniAHzkgDgqBcwOgTMx+gDQQqXCw==
2020""")
2021
2022##file deactivate.bat
2023DEACTIVATE_BAT = convert("""
2024eJxzSE3OyFfIT0vj4ipOLVEI8wwKCXX0iXf1C7Pl4spMU0hJTcvMS01RiPf3cYmHyQYE+fsGhCho
2025cCkAAUibEkTEVhWLMlUlLk6QGixStlyaeCyJDPHw9/Pw93VFsQguim4ZXAJoIUw5DhX47XUM8UCx
2026EchHtwsohN1bILUgw61c/Vy4AJYPYm4=
2027""")
2028
2029##file activate.ps1
2030ACTIVATE_PS = convert("""
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
2117QastYw==
2118""")
2119
2120##file distutils-init.py
2121DISTUTILS_INIT = convert("""
2122eJytV1uL4zYUfvevOE0ottuMW9q3gVDa3aUMXXbLMlDKMBiNrSTqOJKRlMxkf33PkXyRbGe7Dw2E
2123UXTu37lpxLFV2oIyifAncxmOL0xLIfcG+gv80x9VW6maw7o/CANSWWBwFtqeWMPlGY6qPjV8A0bB
2124C4eKSTgZ5LRgFeyErMEeOBhbN+Ipgeizhjtnhkn7DdyjuNLPoCS0l/ayQTG0djwZC08cLXozeMss
2125aG5EzQ0IScpnWtHSTXuxByV/QCmxE7y+eS0uxWeoheaVVfqSJHiU7Mhhi6gULbOHorshkrEnKxpT
21260n3A8Y8SMpuwZx6aoix3ouFlmW8gHRSkeSJ2g7hU+kiHLDaQw3bmRDaTGfTnty7gPm0FHbIBg9U9
2127oh1kZzAFLaue2R6htPCtAda2nGlDSUJ4PZBgCJBGVcwKTAMz/vJiLD+Oin5Z5QlvDPdulC6EsiyE
2128NFzb7McNTKJzbJqzphx92VKRFY1idenzmq3K0emRcbWBD0ryqc4NZGmKOOOX9Pz5x+/l27tP797c
2129f/z0d+4NruGNai8uAM0bfsYaw8itFk8ny41jsfpyO+BWlpqfhcG4yxLdi/0tQqoT4a8Vby382mt8
2130p7XSo7aWGdPBc+b6utaBmCQ7rQKQoWtAuthQCiold2KfJIPTT8xwg9blPumc+YDZC/wYGdAyHpJk
2131vUbHbHWAp5No6pK/WhhLEWrFjUwtPEv1Agf8YmnsuXUQYkeZoHm8ogP16gt2uHoxcEMdf2C6pmbw
2132hUMsWGhanboh4IzzmsIpWs134jVPqD/c74bZHdY69UKKSn/+KfVhxLgUlToemayLMYQOqfEC61bh
2133cbhwaqoGUzIyZRFHPmau5juaWqwRn3mpWmoEA5nhzS5gog/5jbcFQqOZvmBasZtwYlG93k5GEiyw
2134buHhMWLjDarEGpMGB2LFs5nIJkhp/nUmZneFaRth++lieJtHepIvKgx6PJqIlD9X2j6pG1i9x3pZ
21355bHuCPFiirGHeO7McvoXkz786GaKVzC9DSpnOxJdc4xm6NSVq7lNEnKdVlnpu9BNYoKX2Iq3wvgh
2136gGEUM66kK6j4NiyoneuPLSwaCWDxczgaolEWpiMyDVDb7dNuLAbriL8ig8mmeju31oNvQdpnvEPC
21371vAXbWacGRVrGt/uXN/gU0CDDwgooKRrHfTBb1/s9lYZ8ZqOBU0yLvpuP6+K9hLFsvIjeNhBi0KL
2138MlOuWRn3FRwx5oHXjl0YImUx0+gLzjGchrgzca026ETmYJzPD+IpuKzNi8AFn048Thd63OdD86M6
213984zE8yQm0VqXdbbgvub2pKVnS76icBGdeTHHXTKspUmr4NYo/furFLKiMdQzFjHJNcdAnMhltBJK
21400/IKX3DVFqvPJ2dLE7bDBkH0l/PJ29074+F0CsGYOxsb7U3myTUncYfXqnLLfa6sJybX4g+hmcjO
2141kMRBfA1JellfRRKJcyRpxdS4rIl6FdmQCWjo/o9Qz7yKffoP4JHjOvABcRn4CZIT2RH4jnxmfpVG
2142qgLaAvQBNfuO6X0/Ux02nb4FKx3vgP+XnkX0QW9pLy/NsXgdN24dD3LxO2Nwil7Zlc1dqtP3d7/h
2143kzp1/+7hGBuY4pk0XD/0Ao/oTe/XGrfyM773aB7iUhgkpy+dwAMalxMP0DrBcsVw/6p25+/hobP9
2144GBknrWExDhLJ1bwt1NcCNblaFbMKCyvmX0PeRaQ=
2145""")
2146
2147##file distutils.cfg
2148DISTUTILS_CFG = convert("""
2149eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
2150xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
21519FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
2152""")
2153
2154##file activate_this.py
2155ACTIVATE_THIS = convert("""
2156eJyNU01v2zAMvetXEB4K21jmDOstQA4dMGCHbeihlyEIDMWmG62yJEiKE//7kXKdpN2KzYBt8euR
2157fKSyLPs8wiEo8wh4wqZTGou4V6Hm0wJa1cSiTkJdr8+GsoTRHuCotBayiWqQEYGtMCgfD1KjGYBe
21585a3p0cRKiAe2NtLADikftnDco0ko/SFEVgEZ8aRC5GLux7i3BpSJ6J1H+i7A2CjiHq9z7JRZuuQq
2159siwTIvpxJYCeuWaBpwZdhB+yxy/eWz+ZvVSU8C4E9FFZkyxFsvCT/ZzL8gcz9aXVE14Yyp2M+2W0
2160y7n5mp0qN+avKXvbsyyzUqjeWR8hjGE+2iCE1W1tQ82hsCZN9UzlJr+/e/iab8WfqsmPI6pWeUPd
2161FrMsd4H/55poeO9n54COhUs+sZNEzNtg/wanpjpuqHJaxs76HtZryI/K3H7KJ/KDIhqcbJ7kI4ar
2162XL+sMgXnX0D+Te2Iy5xdP8yueSlQB/x/ED2BTAtyE3K4SYUN6AMNfbO63f4lBW3bUJPbTL+mjSxS
2163PyRfJkZRgj+VbFv+EzHFi5pKwUEepa4JslMnwkowSRCXI+m5XvEOvtuBrxHdhLalG0JofYBok6qj
2164YdN2dEngUlbC4PG60M1WEN0piu7Nq7on0mgyyUw3iV1etLo6r/81biWdQ9MWHFaePWZYaq+nmp+t
2165s3az+sj7eA0jfgPfeoN1
2166""")
2167
2168MH_MAGIC = 0xfeedface
2169MH_CIGAM = 0xcefaedfe
2170MH_MAGIC_64 = 0xfeedfacf
2171MH_CIGAM_64 = 0xcffaedfe
2172FAT_MAGIC = 0xcafebabe
2173BIG_ENDIAN = '>'
2174LITTLE_ENDIAN = '<'
2175LC_LOAD_DYLIB = 0xc
2176maxint = majver == 3 and getattr(sys, 'maxsize') or getattr(sys, 'maxint')
2177
2178
2179class fileview(object):
2180 """
2181 A proxy for file-like objects that exposes a given view of a file.
2182 Modified from macholib.
2183 """
2184
2185 def __init__(self, fileobj, start=0, size=maxint):
2186 if isinstance(fileobj, fileview):
2187 self._fileobj = fileobj._fileobj
2188 else:
2189 self._fileobj = fileobj
2190 self._start = start
2191 self._end = start + size
2192 self._pos = 0
2193
2194 def __repr__(self):
2195 return '<fileview [%d, %d] %r>' % (
2196 self._start, self._end, self._fileobj)
2197
2198 def tell(self):
2199 return self._pos
2200
2201 def _checkwindow(self, seekto, op):
2202 if not (self._start <= seekto <= self._end):
2203 raise IOError("%s to offset %d is outside window [%d, %d]" % (
2204 op, seekto, self._start, self._end))
2205
2206 def seek(self, offset, whence=0):
2207 seekto = offset
2208 if whence == os.SEEK_SET:
2209 seekto += self._start
2210 elif whence == os.SEEK_CUR:
2211 seekto += self._start + self._pos
2212 elif whence == os.SEEK_END:
2213 seekto += self._end
2214 else:
2215 raise IOError("Invalid whence argument to seek: %r" % (whence,))
2216 self._checkwindow(seekto, 'seek')
2217 self._fileobj.seek(seekto)
2218 self._pos = seekto - self._start
2219
2220 def write(self, bytes):
2221 here = self._start + self._pos
2222 self._checkwindow(here, 'write')
2223 self._checkwindow(here + len(bytes), 'write')
2224 self._fileobj.seek(here, os.SEEK_SET)
2225 self._fileobj.write(bytes)
2226 self._pos += len(bytes)
2227
2228 def read(self, size=maxint):
2229 assert size >= 0
2230 here = self._start + self._pos
2231 self._checkwindow(here, 'read')
2232 size = min(size, self._end - here)
2233 self._fileobj.seek(here, os.SEEK_SET)
2234 bytes = self._fileobj.read(size)
2235 self._pos += len(bytes)
2236 return bytes
2237
2238
2239def read_data(file, endian, num=1):
2240 """
2241 Read a given number of 32-bits unsigned integers from the given file
2242 with the given endianness.
2243 """
2244 res = struct.unpack(endian + 'L' * num, file.read(num * 4))
2245 if len(res) == 1:
2246 return res[0]
2247 return res
2248
2249
2250def mach_o_change(path, what, value):
2251 """
2252 Replace a given name (what) in any LC_LOAD_DYLIB command found in
2253 the given binary with a new name (value), provided it's shorter.
2254 """
2255
2256 def do_macho(file, bits, endian):
2257 # Read Mach-O header (the magic number is assumed read by the caller)
2258 cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = read_data(file, endian, 6)
2259 # 64-bits header has one more field.
2260 if bits == 64:
2261 read_data(file, endian)
2262 # The header is followed by ncmds commands
2263 for n in range(ncmds):
2264 where = file.tell()
2265 # Read command header
2266 cmd, cmdsize = read_data(file, endian, 2)
2267 if cmd == LC_LOAD_DYLIB:
2268 # The first data field in LC_LOAD_DYLIB commands is the
2269 # offset of the name, starting from the beginning of the
2270 # command.
2271 name_offset = read_data(file, endian)
2272 file.seek(where + name_offset, os.SEEK_SET)
2273 # Read the NUL terminated string
2274 load = file.read(cmdsize - name_offset).decode()
2275 load = load[:load.index('\0')]
2276 # If the string is what is being replaced, overwrite it.
2277 if load == what:
2278 file.seek(where + name_offset, os.SEEK_SET)
2279 file.write(value.encode() + '\0'.encode())
2280 # Seek to the next command
2281 file.seek(where + cmdsize, os.SEEK_SET)
2282
2283 def do_file(file, offset=0, size=maxint):
2284 file = fileview(file, offset, size)
2285 # Read magic number
2286 magic = read_data(file, BIG_ENDIAN)
2287 if magic == FAT_MAGIC:
2288 # Fat binaries contain nfat_arch Mach-O binaries
2289 nfat_arch = read_data(file, BIG_ENDIAN)
2290 for n in range(nfat_arch):
2291 # Read arch header
2292 cputype, cpusubtype, offset, size, align = read_data(file, BIG_ENDIAN, 5)
2293 do_file(file, offset, size)
2294 elif magic == MH_MAGIC:
2295 do_macho(file, 32, BIG_ENDIAN)
2296 elif magic == MH_CIGAM:
2297 do_macho(file, 32, LITTLE_ENDIAN)
2298 elif magic == MH_MAGIC_64:
2299 do_macho(file, 64, BIG_ENDIAN)
2300 elif magic == MH_CIGAM_64:
2301 do_macho(file, 64, LITTLE_ENDIAN)
2302
2303 assert(len(what) >= len(value))
2304 do_file(open(path, 'r+b'))
2305
2306
2307if __name__ == '__main__':
2308 main()
2309
2310## TODO:
2311## Copy python.exe.manifest
2312## Monkeypatch distutils.sysconfig