2
"""Create a "virtual" Python installation
5
# If you change the version here, change it in setup.py
6
# and docs/conf.py as well.
7
__version__ = "1.8.4" # following best practices
8
virtualenv_version = __version__ # legacy, again
22
import distutils.sysconfig
23
from distutils.util import strtobool
27
if sys.version_info < (2, 5):
28
print('ERROR: %s' % sys.exc_info()[1])
29
print('ERROR: this script requires Python 2.5 or greater.')
35
from sets import Set as set
44
import configparser as ConfigParser
47
py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
49
is_jython = sys.platform.startswith('java')
50
is_pypy = hasattr(sys, 'pypy_version_info')
51
is_win = (sys.platform == 'win32')
52
is_cygwin = (sys.platform == 'cygwin')
53
is_darwin = (sys.platform == 'darwin')
54
abiflags = getattr(sys, 'abiflags', '')
56
user_dir = os.path.expanduser('~')
58
default_storage_dir = os.path.join(user_dir, 'virtualenv')
60
default_storage_dir = os.path.join(user_dir, '.virtualenv')
61
default_config_file = os.path.join(default_storage_dir, 'virtualenv.ini')
66
expected_exe = 'jython'
68
expected_exe = 'python'
71
REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
72
'fnmatch', 'locale', 'encodings', 'codecs',
73
'stat', 'UserDict', 'readline', 'copy_reg', 'types',
74
're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
77
REQUIRED_FILES = ['lib-dynload', 'config']
79
majver, minver = sys.version_info[:2]
82
REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
84
REQUIRED_MODULES.extend(['_weakrefset'])
86
REQUIRED_MODULES.extend(['sets', '__future__'])
88
# Some extra modules are needed for Python 3, but different ones
89
# for different versions.
90
REQUIRED_MODULES.extend(['_abcoll', 'warnings', 'linecache', 'abc', 'io',
91
'_weakrefset', 'copyreg', 'tempfile', 'random',
92
'__future__', 'collections', 'keyword', 'tarfile',
93
'shutil', 'struct', 'copy', 'tokenize', 'token',
94
'functools', 'heapq', 'bisect', 'weakref',
97
REQUIRED_FILES[-1] = 'config-%s' % majver
100
platdir = sysconfig.get_config_var('PLATDIR')
101
REQUIRED_FILES.append(platdir)
102
# The whole list of 3.3 modules is reproduced below - the current
103
# uncommented ones are required for 3.3 as of now, but more may be
104
# added as 3.3 development continues.
105
REQUIRED_MODULES.extend([
255
# these are needed to correctly display the exceptions that may happen
256
# during the bootstrap
257
REQUIRED_MODULES.extend(['traceback', 'linecache'])
259
class Logger(object):
262
Logging object for use in command-line script. Allows ranges of
263
levels, to avoid some redundancy of displayed information.
266
DEBUG = logging.DEBUG
268
NOTIFY = (logging.INFO+logging.WARN)/2
269
WARN = WARNING = logging.WARN
270
ERROR = logging.ERROR
271
FATAL = logging.FATAL
273
LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
275
def __init__(self, consumers):
276
self.consumers = consumers
278
self.in_progress = None
279
self.in_progress_hanging = False
281
def debug(self, msg, *args, **kw):
282
self.log(self.DEBUG, msg, *args, **kw)
283
def info(self, msg, *args, **kw):
284
self.log(self.INFO, msg, *args, **kw)
285
def notify(self, msg, *args, **kw):
286
self.log(self.NOTIFY, msg, *args, **kw)
287
def warn(self, msg, *args, **kw):
288
self.log(self.WARN, msg, *args, **kw)
289
def error(self, msg, *args, **kw):
290
self.log(self.ERROR, msg, *args, **kw)
291
def fatal(self, msg, *args, **kw):
292
self.log(self.FATAL, msg, *args, **kw)
293
def log(self, level, msg, *args, **kw):
297
"You may give positional or keyword arguments, not both")
300
for consumer_level, consumer in self.consumers:
301
if self.level_matches(level, consumer_level):
302
if (self.in_progress_hanging
303
and consumer in (sys.stdout, sys.stderr)):
304
self.in_progress_hanging = False
305
sys.stdout.write('\n')
309
rendered = msg % args
312
rendered = ' '*self.indent + rendered
313
if hasattr(consumer, 'write'):
314
consumer.write(rendered+'\n')
318
def start_progress(self, msg):
319
assert not self.in_progress, (
320
"Tried to start_progress(%r) while in_progress %r"
321
% (msg, self.in_progress))
322
if self.level_matches(self.NOTIFY, self._stdout_level()):
323
sys.stdout.write(msg)
325
self.in_progress_hanging = True
327
self.in_progress_hanging = False
328
self.in_progress = msg
330
def end_progress(self, msg='done.'):
331
assert self.in_progress, (
332
"Tried to end_progress without start_progress")
333
if self.stdout_level_matches(self.NOTIFY):
334
if not self.in_progress_hanging:
335
# Some message has been printed out since start_progress
336
sys.stdout.write('...' + self.in_progress + msg + '\n')
339
sys.stdout.write(msg + '\n')
341
self.in_progress = None
342
self.in_progress_hanging = False
344
def show_progress(self):
345
"""If we are in a progress scope, and no log messages have been
346
shown, write out another '.'"""
347
if self.in_progress_hanging:
348
sys.stdout.write('.')
351
def stdout_level_matches(self, level):
352
"""Returns true if a message at this level will go to stdout"""
353
return self.level_matches(level, self._stdout_level())
355
def _stdout_level(self):
356
"""Returns the level that stdout runs at"""
357
for level, consumer in self.consumers:
358
if consumer is sys.stdout:
362
def level_matches(self, level, consumer_level):
365
>>> l.level_matches(3, 4)
367
>>> l.level_matches(3, 2)
369
>>> l.level_matches(slice(None, 3), 3)
371
>>> l.level_matches(slice(None, 3), 2)
373
>>> l.level_matches(slice(1, 3), 1)
375
>>> l.level_matches(slice(2, 3), 1)
378
if isinstance(level, slice):
379
start, stop = level.start, level.stop
380
if start is not None and start > consumer_level:
382
if stop is not None and stop <= consumer_level:
386
return level >= consumer_level
389
def level_for_integer(cls, level):
393
if level >= len(levels):
397
level_for_integer = classmethod(level_for_integer)
399
# create a silent logger just to prevent this from being undefined
400
# will be overridden with requested verbosity main() is called.
401
logger = Logger([(Logger.LEVELS[-1], sys.stdout)])
404
if not os.path.exists(path):
405
logger.info('Creating %s', path)
408
logger.info('Directory %s already exists', path)
410
def copyfileordir(src, dest):
411
if os.path.isdir(src):
412
shutil.copytree(src, dest, True)
414
shutil.copy2(src, dest)
416
def copyfile(src, dest, symlink=True):
417
if not os.path.exists(src):
418
# Some bad symlink in the src
419
logger.warn('Cannot find file %s (bad symlink)', src)
421
if os.path.exists(dest):
422
logger.debug('File %s already exists', dest)
424
if not os.path.exists(os.path.dirname(dest)):
425
logger.info('Creating parent directories for %s' % os.path.dirname(dest))
426
os.makedirs(os.path.dirname(dest))
427
if not os.path.islink(src):
428
srcpath = os.path.abspath(src)
430
srcpath = os.readlink(src)
431
if symlink and hasattr(os, 'symlink') and not is_win:
432
logger.info('Symlinking %s', dest)
434
os.symlink(srcpath, dest)
435
except (OSError, NotImplementedError):
436
logger.info('Symlinking failed, copying to %s', dest)
437
copyfileordir(src, dest)
439
logger.info('Copying to %s', dest)
440
copyfileordir(src, dest)
442
def writefile(dest, content, overwrite=True):
443
if not os.path.exists(dest):
444
logger.info('Writing %s', dest)
446
f.write(content.encode('utf-8'))
453
if c != content.encode("utf-8"):
455
logger.notify('File %s exists with different content; not overwriting', dest)
457
logger.notify('Overwriting %s with new content', dest)
459
f.write(content.encode('utf-8'))
462
logger.info('Content %s already in place', dest)
465
if os.path.exists(dir):
466
logger.notify('Deleting tree %s', dir)
469
logger.info('Do not need to delete %s; already gone', dir)
472
if hasattr(os, 'chmod'):
473
oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777
474
newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777
475
os.chmod(fn, newmode)
476
logger.info('Changed mode of %s to %s', fn, oct(newmode))
478
def _find_file(filename, dirs):
479
for dir in reversed(dirs):
480
files = glob.glob(os.path.join(dir, filename))
481
if files and os.path.isfile(files[0]):
482
return True, files[0]
483
return False, filename
485
def _install_req(py_executable, unzip=False, distribute=False,
486
search_dirs=None, never_download=False):
488
if search_dirs is None:
489
search_dirs = file_search_dirs()
492
egg_path = 'setuptools-*-py%s.egg' % sys.version[:3]
493
found, egg_path = _find_file(egg_path, search_dirs)
494
project_name = 'setuptools'
495
bootstrap_script = EZ_SETUP_PY
498
# Look for a distribute egg (these are not distributed by default,
499
# but can be made available by the user)
500
egg_path = 'distribute-*-py%s.egg' % sys.version[:3]
501
found, egg_path = _find_file(egg_path, search_dirs)
502
project_name = 'distribute'
505
bootstrap_script = DISTRIBUTE_FROM_EGG_PY
508
# NB: egg_path is not None iff tgz_path is None
509
# iff bootstrap_script is a generic setup script accepting
510
# the standard arguments.
512
tgz_path = 'distribute-*.tar.gz'
513
found, tgz_path = _find_file(tgz_path, search_dirs)
514
bootstrap_script = DISTRIBUTE_SETUP_PY
516
if is_jython and os._name == 'nt':
517
# Jython's .bat sys.executable can't handle a command line
518
# argument with newlines
519
fd, ez_setup = tempfile.mkstemp('.py')
520
os.write(fd, bootstrap_script)
522
cmd = [py_executable, ez_setup]
524
cmd = [py_executable, '-c', bootstrap_script]
525
if unzip and egg_path:
526
cmd.append('--always-unzip')
528
remove_from_env = ['__PYVENV_LAUNCHER__']
529
if logger.stdout_level_matches(logger.DEBUG) and egg_path:
532
old_chdir = os.getcwd()
533
if egg_path is not None and os.path.exists(egg_path):
534
logger.info('Using existing %s egg: %s' % (project_name, egg_path))
536
if os.environ.get('PYTHONPATH'):
537
env['PYTHONPATH'] = egg_path + os.path.pathsep + os.environ['PYTHONPATH']
539
env['PYTHONPATH'] = egg_path
540
elif tgz_path is not None and os.path.exists(tgz_path):
541
# Found a tgz source dist, let's chdir
542
logger.info('Using existing %s egg: %s' % (project_name, tgz_path))
543
os.chdir(os.path.dirname(tgz_path))
544
# in this case, we want to be sure that PYTHONPATH is unset (not
545
# just empty, really unset), else CPython tries to import the
546
# site.py that it's in virtualenv_support
547
remove_from_env.append('PYTHONPATH')
549
logger.fatal("Can't find any local distributions of %s to install "
550
"and --never-download is set. Either re-run virtualenv "
551
"without the --never-download option, or place a %s "
552
"distribution (%s) in one of these "
553
"locations: %r" % (project_name, project_name,
554
egg_path or tgz_path,
558
logger.info('No %s egg found; downloading' % project_name)
559
cmd.extend(['--always-copy', '-U', project_name])
561
logger.info('No %s tgz found; downloading' % project_name)
562
logger.start_progress('Installing %s...' % project_name)
565
if project_name == 'distribute':
566
env['DONT_PATCH_SETUPTOOLS'] = 'true'
568
def _filter_ez_setup(line):
569
return filter_ez_setup(line, project_name)
571
if not os.access(os.getcwd(), os.W_OK):
572
cwd = tempfile.mkdtemp()
573
if tgz_path is not None and os.path.exists(tgz_path):
574
# the current working dir is hostile, let's copy the
575
# tarball to a temp dir
576
target = os.path.join(cwd, os.path.split(tgz_path)[-1])
577
shutil.copy(tgz_path, target)
579
call_subprocess(cmd, show_stdout=False,
580
filter_stdout=_filter_ez_setup,
582
remove_from_env=remove_from_env,
586
logger.end_progress()
589
if os.getcwd() != old_chdir:
591
if is_jython and os._name == 'nt':
594
def file_search_dirs():
595
here = os.path.dirname(os.path.abspath(__file__))
597
join(here, 'virtualenv_support')]
598
if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
599
# Probably some boot script; just in case virtualenv is installed...
605
dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
606
return [d for d in dirs if os.path.isdir(d)]
608
def install_setuptools(py_executable, unzip=False,
609
search_dirs=None, never_download=False):
610
_install_req(py_executable, unzip,
611
search_dirs=search_dirs, never_download=never_download)
613
def install_distribute(py_executable, unzip=False,
614
search_dirs=None, never_download=False):
615
_install_req(py_executable, unzip, distribute=True,
616
search_dirs=search_dirs, never_download=never_download)
618
_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I)
619
def install_pip(py_executable, search_dirs=None, never_download=False):
620
if search_dirs is None:
621
search_dirs = file_search_dirs()
624
for dir in search_dirs:
625
filenames.extend([join(dir, fn) for fn in os.listdir(dir)
626
if _pip_re.search(fn)])
627
filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)]
629
filenames = [filename for basename, i, filename in filenames]
633
filename = filenames[-1]
634
easy_install_script = 'easy_install'
636
easy_install_script = 'easy_install-script.py'
637
# There's two subtle issues here when invoking easy_install.
638
# 1. On unix-like systems the easy_install script can *only* be executed
639
# directly if its full filesystem path is no longer than 78 characters.
640
# 2. A work around to [1] is to use the `python path/to/easy_install foo`
641
# pattern, but that breaks if the path contains non-ASCII characters, as
642
# you can't put the file encoding declaration before the shebang line.
643
# The solution is to use Python's -x flag to skip the first line of the
644
# script (and any ASCII decoding errors that may have occurred in that line)
645
cmd = [py_executable, '-x', join(os.path.dirname(py_executable), easy_install_script), filename]
646
# jython and pypy don't yet support -x
647
if is_jython or is_pypy:
649
if filename == 'pip':
651
logger.fatal("Can't find any local distributions of pip to install "
652
"and --never-download is set. Either re-run virtualenv "
653
"without the --never-download option, or place a pip "
654
"source distribution (zip/tar.gz/tar.bz2) in one of these "
655
"locations: %r" % search_dirs)
657
logger.info('Installing pip from network...')
659
logger.info('Installing existing %s distribution: %s' % (
660
os.path.basename(filename), filename))
661
logger.start_progress('Installing pip...')
663
def _filter_setup(line):
664
return filter_ez_setup(line, 'pip')
666
call_subprocess(cmd, show_stdout=False,
667
filter_stdout=_filter_setup)
670
logger.end_progress()
672
def filter_ez_setup(line, project_name='setuptools'):
675
if project_name == 'distribute':
676
for prefix in ('Extracting', 'Now working', 'Installing', 'Before',
677
'Scanning', 'Setuptools', 'Egg', 'Already',
678
'running', 'writing', 'reading', 'installing',
679
'creating', 'copying', 'byte-compiling', 'removing',
681
if line.startswith(prefix):
684
for prefix in ['Reading ', 'Best match', 'Processing setuptools',
685
'Copying setuptools', 'Adding setuptools',
686
'Installing ', 'Installed ']:
687
if line.startswith(prefix):
692
class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter):
694
Custom help formatter for use in ConfigOptionParser that updates
695
the defaults before expanding them, allowing them to show up correctly
698
def expand_default(self, option):
699
if self.parser is not None:
700
self.parser.update_defaults(self.parser.defaults)
701
return optparse.IndentedHelpFormatter.expand_default(self, option)
704
class ConfigOptionParser(optparse.OptionParser):
706
Custom option parser which updates its defaults by by checking the
707
configuration files and environmental variables
709
def __init__(self, *args, **kwargs):
710
self.config = ConfigParser.RawConfigParser()
711
self.files = self.get_config_files()
712
self.config.read(self.files)
713
optparse.OptionParser.__init__(self, *args, **kwargs)
715
def get_config_files(self):
716
config_file = os.environ.get('VIRTUALENV_CONFIG_FILE', False)
717
if config_file and os.path.exists(config_file):
719
return [default_config_file]
721
def update_defaults(self, defaults):
723
Updates the given defaults with values from the config files and
724
the environ. Does a little special handling for certain types of
727
# Then go and look for the other sources of configuration:
730
config.update(dict(self.get_config_section('virtualenv')))
731
# 2. environmental variables
732
config.update(dict(self.get_environ_vars()))
733
# Then set the options with those values
734
for key, val in config.items():
735
key = key.replace('_', '-')
736
if not key.startswith('--'):
737
key = '--%s' % key # only prefer long opts
738
option = self.get_option(key)
739
if option is not None:
740
# ignore empty values
743
# handle multiline configs
744
if option.action == 'append':
748
if option.action == 'store_false':
749
val = not strtobool(val)
750
elif option.action in ('store_true', 'count'):
753
val = option.convert_value(key, val)
754
except optparse.OptionValueError:
755
e = sys.exc_info()[1]
756
print("An error occured during configuration: %s" % e)
758
defaults[option.dest] = val
761
def get_config_section(self, name):
763
Get a section of a configuration
765
if self.config.has_section(name):
766
return self.config.items(name)
769
def get_environ_vars(self, prefix='VIRTUALENV_'):
771
Returns a generator with all environmental vars with prefix VIRTUALENV
773
for key, val in os.environ.items():
774
if key.startswith(prefix):
775
yield (key.replace(prefix, '').lower(), val)
777
def get_default_values(self):
779
Overridding to make updating the defaults after instantiation of
780
the option parser possible, update_defaults() does the dirty work.
782
if not self.process_default_values:
783
# Old, pre-Optik 1.5 behaviour.
784
return optparse.Values(self.defaults)
786
defaults = self.update_defaults(self.defaults.copy()) # ours
787
for option in self._get_all_options():
788
default = defaults.get(option.dest)
789
if isinstance(default, basestring):
790
opt_str = option.get_opt_string()
791
defaults[option.dest] = option.check_value(opt_str, default)
792
return optparse.Values(defaults)
796
parser = ConfigOptionParser(
797
version=virtualenv_version,
798
usage="%prog [OPTIONS] DEST_DIR",
799
formatter=UpdatingDefaultsHelpFormatter())
806
help="Increase verbosity")
813
help='Decrease verbosity')
818
metavar='PYTHON_EXE',
819
help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
820
'interpreter to create the new environment. The default is the interpreter that '
821
'virtualenv was installed with (%s)' % sys.executable)
827
help="Clear out the non-root install and start from scratch")
829
parser.set_defaults(system_site_packages=False)
831
'--no-site-packages',
832
dest='system_site_packages',
833
action='store_false',
834
help="Don't give access to the global site-packages dir to the "
835
"virtual environment (default)")
838
'--system-site-packages',
839
dest='system_site_packages',
841
help="Give access to the global site-packages dir to the "
842
"virtual environment")
845
'--unzip-setuptools',
846
dest='unzip_setuptools',
848
help="Unzip Setuptools or Distribute when installing it")
854
help='Make an EXISTING virtualenv environment relocatable. '
855
'This fixes up scripts and makes all .pth files relative')
858
'--distribute', '--use-distribute', # the second option is for legacy reasons here. Hi Kenneth!
859
dest='use_distribute',
861
help='Use Distribute instead of Setuptools. Set environ variable '
862
'VIRTUALENV_DISTRIBUTE to make it the default ')
866
dest='use_distribute',
867
action='store_false',
868
help='Use Setuptools instead of Distribute. Set environ variable '
869
'VIRTUALENV_SETUPTOOLS to make it the default ')
871
# Set this to True to use distribute by default, even in Python 2.
872
parser.set_defaults(use_distribute=False)
874
default_search_dirs = file_search_dirs()
876
'--extra-search-dir',
879
default=default_search_dirs,
880
help="Directory to look for setuptools/distribute/pip distributions in. "
881
"You can add any number of additional --extra-search-dir paths.")
885
dest="never_download",
887
help="Never download anything from the network. Instead, virtualenv will fail "
888
"if local distributions of setuptools/distribute/pip are not present.")
893
help='Provides an alternative prompt prefix for this environment')
895
if 'extend_parser' in globals():
896
extend_parser(parser)
898
options, args = parser.parse_args()
902
if 'adjust_options' in globals():
903
adjust_options(options, args)
905
verbosity = options.verbose - options.quiet
906
logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)])
908
if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
909
env = os.environ.copy()
910
interpreter = resolve_interpreter(options.python)
911
if interpreter == sys.executable:
912
logger.warn('Already using interpreter %s' % interpreter)
914
logger.notify('Running virtualenv with interpreter %s' % interpreter)
915
env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
917
if file.endswith('.pyc'):
919
popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
920
raise SystemExit(popen.wait())
922
# Force --distribute on Python 3, since setuptools is not available.
924
options.use_distribute = True
926
if os.environ.get('PYTHONDONTWRITEBYTECODE') and not options.use_distribute:
928
"The PYTHONDONTWRITEBYTECODE environment variable is "
929
"not compatible with setuptools. Either use --distribute "
930
"or unset PYTHONDONTWRITEBYTECODE.")
933
print('You must provide a DEST_DIR')
937
print('There must be only one argument: DEST_DIR (you gave %s)' % (
944
if os.environ.get('WORKING_ENV'):
945
logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
946
logger.fatal('Please deactivate your workingenv, then re-run this script')
949
if 'PYTHONHOME' in os.environ:
950
logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it')
951
del os.environ['PYTHONHOME']
953
if options.relocatable:
954
make_environment_relocatable(home_dir)
957
create_environment(home_dir,
958
site_packages=options.system_site_packages,
960
unzip_setuptools=options.unzip_setuptools,
961
use_distribute=options.use_distribute,
962
prompt=options.prompt,
963
search_dirs=options.search_dirs,
964
never_download=options.never_download)
965
if 'after_install' in globals():
966
after_install(options, home_dir)
968
def call_subprocess(cmd, show_stdout=True,
969
filter_stdout=None, cwd=None,
970
raise_on_returncode=True, extra_env=None,
971
remove_from_env=None):
975
part = part[:20]+"..."+part[-20:]
976
if ' ' in part or '\n' in part or '"' in part or "'" in part:
977
part = '"%s"' % part.replace('"', '\\"')
978
if hasattr(part, 'decode'):
980
part = part.decode(sys.getdefaultencoding())
981
except UnicodeDecodeError:
982
part = part.decode(sys.getfilesystemencoding())
983
cmd_parts.append(part)
984
cmd_desc = ' '.join(cmd_parts)
988
stdout = subprocess.PIPE
989
logger.debug("Running command %s" % cmd_desc)
990
if extra_env or remove_from_env:
991
env = os.environ.copy()
993
env.update(extra_env)
995
for varname in remove_from_env:
996
env.pop(varname, None)
1000
proc = subprocess.Popen(
1001
cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
1004
e = sys.exc_info()[1]
1006
"Error %s while executing command %s" % (e, cmd_desc))
1009
if stdout is not None:
1010
stdout = proc.stdout
1011
encoding = sys.getdefaultencoding()
1012
fs_encoding = sys.getfilesystemencoding()
1014
line = stdout.readline()
1016
line = line.decode(encoding)
1017
except UnicodeDecodeError:
1018
line = line.decode(fs_encoding)
1021
line = line.rstrip()
1022
all_output.append(line)
1024
level = filter_stdout(line)
1025
if isinstance(level, tuple):
1027
logger.log(level, line)
1028
if not logger.stdout_level_matches(level):
1029
logger.show_progress()
1036
if raise_on_returncode:
1038
logger.notify('Complete output from command %s:' % cmd_desc)
1039
logger.notify('\n'.join(all_output) + '\n----------------------------------------')
1041
"Command %s failed with error code %s"
1042
% (cmd_desc, proc.returncode))
1045
"Command %s had error code %s"
1046
% (cmd_desc, proc.returncode))
1049
def create_environment(home_dir, site_packages=False, clear=False,
1050
unzip_setuptools=False, use_distribute=False,
1051
prompt=None, search_dirs=None, never_download=False):
1053
Creates a new environment in ``home_dir``.
1055
If ``site_packages`` is true, then the global ``site-packages/``
1056
directory will be on the path.
1058
If ``clear`` is true (default False) then the environment will
1061
home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
1063
py_executable = os.path.abspath(install_python(
1064
home_dir, lib_dir, inc_dir, bin_dir,
1065
site_packages=site_packages, clear=clear))
1067
install_distutils(home_dir)
1070
install_distribute(py_executable, unzip=unzip_setuptools,
1071
search_dirs=search_dirs, never_download=never_download)
1073
install_setuptools(py_executable, unzip=unzip_setuptools,
1074
search_dirs=search_dirs, never_download=never_download)
1076
install_pip(py_executable, search_dirs=search_dirs, never_download=never_download)
1078
install_activate(home_dir, bin_dir, prompt)
1080
def is_executable_file(fpath):
1081
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
1083
def path_locations(home_dir):
1084
"""Return the path locations for the environment (where libraries are,
1085
where scripts go, etc)"""
1086
# XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
1087
# prefix arg is broken: http://bugs.python.org/issue3386
1089
# Windows has lots of problems with executables with spaces in
1090
# the name; this function will remove them (using the ~1
1095
GetShortPathName = ctypes.windll.kernel32.GetShortPathNameW
1096
size = max(len(home_dir)+1, 256)
1097
buf = ctypes.create_unicode_buffer(size)
1102
ret = GetShortPathName(u(home_dir), buf, size)
1104
print('Error: the path "%s" has a space in it' % home_dir)
1105
print('We could not determine the short pathname for it.')
1108
home_dir = str(buf.value)
1109
lib_dir = join(home_dir, 'Lib')
1110
inc_dir = join(home_dir, 'Include')
1111
bin_dir = join(home_dir, 'Scripts')
1113
lib_dir = join(home_dir, 'Lib')
1114
inc_dir = join(home_dir, 'Include')
1115
bin_dir = join(home_dir, 'bin')
1118
inc_dir = join(home_dir, 'include')
1119
bin_dir = join(home_dir, 'bin')
1121
lib_dir = join(home_dir, 'lib', py_version)
1122
multiarch_exec = '/usr/bin/multiarch-platform'
1123
if is_executable_file(multiarch_exec):
1124
# In Mageia (2) and Mandriva distros the include dir must be like:
1125
# virtualenv/include/multiarch-x86_64-linux/python2.7
1126
# instead of being virtualenv/include/python2.7
1127
p = subprocess.Popen(multiarch_exec, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
1128
stdout, stderr = p.communicate()
1129
# stdout.strip is needed to remove newline character
1130
inc_dir = join(home_dir, 'include', stdout.strip(), py_version + abiflags)
1132
inc_dir = join(home_dir, 'include', py_version + abiflags)
1133
bin_dir = join(home_dir, 'bin')
1134
return home_dir, lib_dir, inc_dir, bin_dir
1137
def change_prefix(filename, dst_prefix):
1138
prefixes = [sys.prefix]
1142
os.path.join("/Library/Python", sys.version[:3], "site-packages"),
1143
os.path.join(sys.prefix, "Extras", "lib", "python"),
1144
os.path.join("~", "Library", "Python", sys.version[:3], "site-packages"),
1145
# Python 2.6 no-frameworks
1146
os.path.join("~", ".local", "lib","python", sys.version[:3], "site-packages"),
1147
# System Python 2.7 on OSX Mountain Lion
1148
os.path.join("~", "Library", "Python", sys.version[:3], "lib", "python", "site-packages")))
1150
if hasattr(sys, 'real_prefix'):
1151
prefixes.append(sys.real_prefix)
1152
if hasattr(sys, 'base_prefix'):
1153
prefixes.append(sys.base_prefix)
1154
prefixes = list(map(os.path.expanduser, prefixes))
1155
prefixes = list(map(os.path.abspath, prefixes))
1156
# Check longer prefixes first so we don't split in the middle of a filename
1157
prefixes = sorted(prefixes, key=len, reverse=True)
1158
filename = os.path.abspath(filename)
1159
for src_prefix in prefixes:
1160
if filename.startswith(src_prefix):
1161
_, relpath = filename.split(src_prefix, 1)
1162
if src_prefix != os.sep: # sys.prefix == "/"
1163
assert relpath[0] == os.sep
1164
relpath = relpath[1:]
1165
return join(dst_prefix, relpath)
1166
assert False, "Filename %s does not start with any of these prefixes: %s" % \
1167
(filename, prefixes)
1169
def copy_required_modules(dst_prefix):
1171
# If we are running under -p, we need to remove the current
1172
# directory from sys.path temporarily here, so that we
1173
# definitely get the modules from the site directory of
1174
# the interpreter we are running under, not the one
1175
# virtualenv.py is installed under (which might lead to py2/py3
1176
# incompatibility issues)
1177
_prev_sys_path = sys.path
1178
if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
1179
sys.path = sys.path[1:]
1181
for modname in REQUIRED_MODULES:
1182
if modname in sys.builtin_module_names:
1183
logger.info("Ignoring built-in bootstrap module: %s" % modname)
1186
f, filename, _ = imp.find_module(modname)
1188
logger.info("Cannot import bootstrap module: %s" % modname)
1192
# special-case custom readline.so on OS X:
1193
if modname == 'readline' and sys.platform == 'darwin' and not filename.endswith(join('lib-dynload', 'readline.so')):
1194
dst_filename = join(dst_prefix, 'lib', 'python%s' % sys.version[:3], 'readline.so')
1196
dst_filename = change_prefix(filename, dst_prefix)
1197
copyfile(filename, dst_filename)
1198
if filename.endswith('.pyc'):
1199
pyfile = filename[:-1]
1200
if os.path.exists(pyfile):
1201
copyfile(pyfile, dst_filename[:-1])
1203
sys.path = _prev_sys_path
1206
def subst_path(prefix_path, prefix, home_dir):
1207
prefix_path = os.path.normpath(prefix_path)
1208
prefix = os.path.normpath(prefix)
1209
home_dir = os.path.normpath(home_dir)
1210
if not prefix_path.startswith(prefix):
1211
logger.warn('Path not in prefix %r %r', prefix_path, prefix)
1213
return prefix_path.replace(prefix, home_dir, 1)
1216
def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
1217
"""Install just the base environment, no distutils patches etc"""
1218
if sys.executable.startswith(bin_dir):
1219
print('Please use the *system* python to run this script')
1224
## FIXME: why not delete it?
1225
## Maybe it should delete everything with #!/path/to/venv/python in it
1226
logger.notify('Not deleting %s', bin_dir)
1228
if hasattr(sys, 'real_prefix'):
1229
logger.notify('Using real prefix %r' % sys.real_prefix)
1230
prefix = sys.real_prefix
1231
elif hasattr(sys, 'base_prefix'):
1232
logger.notify('Using base prefix %r' % sys.base_prefix)
1233
prefix = sys.base_prefix
1238
stdlib_dirs = [os.path.dirname(os.__file__)]
1240
stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
1242
stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
1243
if hasattr(os, 'symlink'):
1244
logger.info('Symlinking Python bootstrap modules')
1246
logger.info('Copying Python bootstrap modules')
1249
# copy required files...
1250
for stdlib_dir in stdlib_dirs:
1251
if not os.path.isdir(stdlib_dir):
1253
for fn in os.listdir(stdlib_dir):
1254
bn = os.path.splitext(fn)[0]
1255
if fn != 'site-packages' and bn in REQUIRED_FILES:
1256
copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
1258
copy_required_modules(home_dir)
1261
mkdir(join(lib_dir, 'site-packages'))
1263
site_filename = site.__file__
1264
if site_filename.endswith('.pyc'):
1265
site_filename = site_filename[:-1]
1266
elif site_filename.endswith('$py.class'):
1267
site_filename = site_filename.replace('$py.class', '.py')
1268
site_filename_dst = change_prefix(site_filename, home_dir)
1269
site_dir = os.path.dirname(site_filename_dst)
1270
writefile(site_filename_dst, SITE_PY)
1271
writefile(join(site_dir, 'orig-prefix.txt'), prefix)
1272
site_packages_filename = join(site_dir, 'no-global-site-packages.txt')
1273
if not site_packages:
1274
writefile(site_packages_filename, '')
1276
if is_pypy or is_win:
1277
stdinc_dir = join(prefix, 'include')
1279
stdinc_dir = join(prefix, 'include', py_version + abiflags)
1280
if os.path.exists(stdinc_dir):
1281
copyfile(stdinc_dir, inc_dir)
1283
logger.debug('No include dir %s' % stdinc_dir)
1285
platinc_dir = distutils.sysconfig.get_python_inc(plat_specific=1)
1286
if platinc_dir != stdinc_dir:
1287
platinc_dest = distutils.sysconfig.get_python_inc(
1288
plat_specific=1, prefix=home_dir)
1289
if platinc_dir == platinc_dest:
1290
# Do platinc_dest manually due to a CPython bug;
1291
# not http://bugs.python.org/issue3386 but a close cousin
1292
platinc_dest = subst_path(platinc_dir, prefix, home_dir)
1294
# PyPy's stdinc_dir and prefix are relative to the original binary
1295
# (traversing virtualenvs), whereas the platinc_dir is relative to
1296
# the inner virtualenv and ignores the prefix argument.
1297
# This seems more evolved than designed.
1298
copyfile(platinc_dir, platinc_dest)
1300
# pypy never uses exec_prefix, just ignore it
1301
if sys.exec_prefix != prefix and not is_pypy:
1303
exec_dir = join(sys.exec_prefix, 'lib')
1305
exec_dir = join(sys.exec_prefix, 'Lib')
1307
exec_dir = join(sys.exec_prefix, 'lib', py_version)
1308
for fn in os.listdir(exec_dir):
1309
copyfile(join(exec_dir, fn), join(lib_dir, fn))
1312
# Jython has either jython-dev.jar and javalib/ dir, or just
1314
for name in 'jython-dev.jar', 'javalib', 'jython.jar':
1315
src = join(prefix, name)
1316
if os.path.exists(src):
1317
copyfile(src, join(home_dir, name))
1318
# XXX: registry should always exist after Jython 2.5rc1
1319
src = join(prefix, 'registry')
1320
if os.path.exists(src):
1321
copyfile(src, join(home_dir, 'registry'), symlink=False)
1322
copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
1326
py_executable = join(bin_dir, os.path.basename(sys.executable))
1327
if 'Python.framework' in prefix:
1328
# OS X framework builds cause validation to break
1329
# https://github.com/pypa/virtualenv/issues/322
1330
if os.environ.get('__PYVENV_LAUNCHER__'):
1331
os.unsetenv('__PYVENV_LAUNCHER__')
1332
if re.search(r'/Python(?:-32|-64)*$', py_executable):
1333
# The name of the python executable is not quite what
1334
# we want, rename it.
1335
py_executable = os.path.join(
1336
os.path.dirname(py_executable), 'python')
1338
logger.notify('New %s executable in %s', expected_exe, py_executable)
1339
pcbuild_dir = os.path.dirname(sys.executable)
1340
pyd_pth = os.path.join(lib_dir, 'site-packages', 'virtualenv_builddir_pyd.pth')
1341
if is_win and os.path.exists(os.path.join(pcbuild_dir, 'build.bat')):
1342
logger.notify('Detected python running from build directory %s', pcbuild_dir)
1343
logger.notify('Writing .pth file linking to build directory for *.pyd files')
1344
writefile(pyd_pth, pcbuild_dir)
1347
if os.path.exists(pyd_pth):
1348
logger.info('Deleting %s (not Windows env or not build directory python)' % pyd_pth)
1351
if sys.executable != py_executable:
1352
## FIXME: could I just hard link?
1353
executable = sys.executable
1354
if is_cygwin and os.path.exists(executable + '.exe'):
1355
# Cygwin misreports sys.executable sometimes
1356
executable += '.exe'
1357
py_executable += '.exe'
1358
logger.info('Executable actually exists in %s' % executable)
1359
shutil.copyfile(executable, py_executable)
1360
make_exe(py_executable)
1361
if is_win or is_cygwin:
1362
pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
1363
if os.path.exists(pythonw):
1364
logger.info('Also created pythonw.exe')
1365
shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
1366
python_d = os.path.join(os.path.dirname(sys.executable), 'python_d.exe')
1367
python_d_dest = os.path.join(os.path.dirname(py_executable), 'python_d.exe')
1368
if os.path.exists(python_d):
1369
logger.info('Also created python_d.exe')
1370
shutil.copyfile(python_d, python_d_dest)
1371
elif os.path.exists(python_d_dest):
1372
logger.info('Removed python_d.exe as it is no longer at the source')
1373
os.unlink(python_d_dest)
1374
# we need to copy the DLL to enforce that windows will load the correct one.
1375
# may not exist if we are cygwin.
1376
py_executable_dll = 'python%s%s.dll' % (
1377
sys.version_info[0], sys.version_info[1])
1378
py_executable_dll_d = 'python%s%s_d.dll' % (
1379
sys.version_info[0], sys.version_info[1])
1380
pythondll = os.path.join(os.path.dirname(sys.executable), py_executable_dll)
1381
pythondll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d)
1382
pythondll_d_dest = os.path.join(os.path.dirname(py_executable), py_executable_dll_d)
1383
if os.path.exists(pythondll):
1384
logger.info('Also created %s' % py_executable_dll)
1385
shutil.copyfile(pythondll, os.path.join(os.path.dirname(py_executable), py_executable_dll))
1386
if os.path.exists(pythondll_d):
1387
logger.info('Also created %s' % py_executable_dll_d)
1388
shutil.copyfile(pythondll_d, pythondll_d_dest)
1389
elif os.path.exists(pythondll_d_dest):
1390
logger.info('Removed %s as the source does not exist' % pythondll_d_dest)
1391
os.unlink(pythondll_d_dest)
1393
# make a symlink python --> pypy-c
1394
python_executable = os.path.join(os.path.dirname(py_executable), 'python')
1395
if sys.platform in ('win32', 'cygwin'):
1396
python_executable += '.exe'
1397
logger.info('Also created executable %s' % python_executable)
1398
copyfile(py_executable, python_executable)
1401
for name in 'libexpat.dll', 'libpypy.dll', 'libpypy-c.dll', 'libeay32.dll', 'ssleay32.dll', 'sqlite.dll':
1402
src = join(prefix, name)
1403
if os.path.exists(src):
1404
copyfile(src, join(bin_dir, name))
1406
if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
1407
secondary_exe = os.path.join(os.path.dirname(py_executable),
1409
py_executable_ext = os.path.splitext(py_executable)[1]
1410
if py_executable_ext == '.exe':
1411
# python2.4 gives an extension of '.4' :P
1412
secondary_exe += py_executable_ext
1413
if os.path.exists(secondary_exe):
1414
logger.warn('Not overwriting existing %s script %s (you must use %s)'
1415
% (expected_exe, secondary_exe, py_executable))
1417
logger.notify('Also creating executable in %s' % secondary_exe)
1418
shutil.copyfile(sys.executable, secondary_exe)
1419
make_exe(secondary_exe)
1421
if '.framework' in prefix:
1422
if 'Python.framework' in prefix:
1423
logger.debug('MacOSX Python framework detected')
1424
# Make sure we use the the embedded interpreter inside
1425
# the framework, even if sys.executable points to
1426
# the stub executable in ${sys.prefix}/bin
1427
# See http://groups.google.com/group/python-virtualenv/
1428
# browse_thread/thread/17cab2f85da75951
1429
original_python = os.path.join(
1430
prefix, 'Resources/Python.app/Contents/MacOS/Python')
1432
logger.debug('EPD framework detected')
1433
original_python = os.path.join(prefix, 'bin/python')
1434
shutil.copy(original_python, py_executable)
1436
# Copy the framework's dylib into the virtual
1438
virtual_lib = os.path.join(home_dir, '.Python')
1440
if os.path.exists(virtual_lib):
1441
os.unlink(virtual_lib)
1443
os.path.join(prefix, 'Python'),
1446
# And then change the install_name of the copied python executable
1448
mach_o_change(py_executable,
1449
os.path.join(prefix, 'Python'),
1450
'@executable_path/../.Python')
1452
e = sys.exc_info()[1]
1453
logger.warn("Could not call mach_o_change: %s. "
1454
"Trying to call install_name_tool instead." % e)
1457
["install_name_tool", "-change",
1458
os.path.join(prefix, 'Python'),
1459
'@executable_path/../.Python',
1462
logger.fatal("Could not call install_name_tool -- you must "
1463
"have Apple's development tools installed")
1467
# Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist
1468
py_exe_version_major = 'python%s' % sys.version_info[0]
1469
py_exe_version_major_minor = 'python%s.%s' % (
1470
sys.version_info[0], sys.version_info[1])
1471
py_exe_no_version = 'python'
1472
required_symlinks = [ py_exe_no_version, py_exe_version_major,
1473
py_exe_version_major_minor ]
1475
py_executable_base = os.path.basename(py_executable)
1477
if py_executable_base in required_symlinks:
1478
# Don't try to symlink to yourself.
1479
required_symlinks.remove(py_executable_base)
1481
for pth in required_symlinks:
1482
full_pth = join(bin_dir, pth)
1483
if os.path.exists(full_pth):
1485
os.symlink(py_executable_base, full_pth)
1487
if is_win and ' ' in py_executable:
1488
# There's a bug with subprocess on Windows when using a first
1489
# argument that has a space in it. Instead we have to quote
1491
py_executable = '"%s"' % py_executable
1492
# NOTE: keep this check as one line, cmd.exe doesn't cope with line breaks
1493
cmd = [py_executable, '-c', 'import sys;out=sys.stdout;'
1494
'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))']
1495
logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
1497
proc = subprocess.Popen(cmd,
1498
stdout=subprocess.PIPE)
1499
proc_stdout, proc_stderr = proc.communicate()
1501
e = sys.exc_info()[1]
1502
if e.errno == errno.EACCES:
1503
logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e))
1508
proc_stdout = proc_stdout.strip().decode("utf-8")
1509
proc_stdout = os.path.normcase(os.path.abspath(proc_stdout))
1510
norm_home_dir = os.path.normcase(os.path.abspath(home_dir))
1511
if hasattr(norm_home_dir, 'decode'):
1512
norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding())
1513
if proc_stdout != norm_home_dir:
1515
'ERROR: The executable %s is not functioning' % py_executable)
1517
'ERROR: It thinks sys.prefix is %r (should be %r)'
1518
% (proc_stdout, norm_home_dir))
1520
'ERROR: virtualenv is not compatible with this system or executable')
1523
'Note: some Windows users have reported this error when they '
1524
'installed Python for "Only this user" or have multiple '
1525
'versions of Python installed. Copying the appropriate '
1526
'PythonXX.dll to the virtualenv Scripts/ directory may fix '
1530
logger.info('Got sys.prefix result: %r' % proc_stdout)
1532
pydistutils = os.path.expanduser('~/.pydistutils.cfg')
1533
if os.path.exists(pydistutils):
1534
logger.notify('Please make sure you remove any previous custom paths from '
1535
'your %s file.' % pydistutils)
1536
## FIXME: really this should be calculated earlier
1538
fix_local_scheme(home_dir)
1541
if os.path.exists(site_packages_filename):
1542
logger.info('Deleting %s' % site_packages_filename)
1543
os.unlink(site_packages_filename)
1545
return py_executable
1548
def install_activate(home_dir, bin_dir, prompt=None):
1549
home_dir = os.path.abspath(home_dir)
1550
if is_win or is_jython and os._name == 'nt':
1552
'activate.bat': ACTIVATE_BAT,
1553
'deactivate.bat': DEACTIVATE_BAT,
1554
'activate.ps1': ACTIVATE_PS,
1557
# MSYS needs paths of the form /c/path/to/file
1558
drive, tail = os.path.splitdrive(home_dir.replace(os.sep, '/'))
1559
home_dir_msys = (drive and "/%s%s" or "%s%s") % (drive[:1], tail)
1561
# Run-time conditional enables (basic) Cygwin compatibility
1562
home_dir_sh = ("""$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '%s'; else echo '%s'; fi;)""" %
1563
(home_dir, home_dir_msys))
1564
files['activate'] = ACTIVATE_SH.replace('__VIRTUAL_ENV__', home_dir_sh)
1567
files = {'activate': ACTIVATE_SH}
1569
# suppling activate.fish in addition to, not instead of, the
1570
# bash script support.
1571
files['activate.fish'] = ACTIVATE_FISH
1573
# same for csh/tcsh support...
1574
files['activate.csh'] = ACTIVATE_CSH
1576
files['activate_this.py'] = ACTIVATE_THIS
1577
if hasattr(home_dir, 'decode'):
1578
home_dir = home_dir.decode(sys.getfilesystemencoding())
1579
vname = os.path.basename(home_dir)
1580
for name, content in files.items():
1581
content = content.replace('__VIRTUAL_PROMPT__', prompt or '')
1582
content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)
1583
content = content.replace('__VIRTUAL_ENV__', home_dir)
1584
content = content.replace('__VIRTUAL_NAME__', vname)
1585
content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
1586
writefile(os.path.join(bin_dir, name), content)
1588
def install_distutils(home_dir):
1589
distutils_path = change_prefix(distutils.__path__[0], home_dir)
1590
mkdir(distutils_path)
1591
## FIXME: maybe this prefix setting should only be put in place if
1592
## there's a local distutils.cfg with a prefix setting?
1593
home_dir = os.path.abspath(home_dir)
1594
## FIXME: this is breaking things, removing for now:
1595
#distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
1596
writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
1597
writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
1599
def fix_local_scheme(home_dir):
1601
Platforms that use the "posix_local" install scheme (like Ubuntu with
1602
Python 2.7) need to be given an additional "local" location, sigh.
1609
if sysconfig._get_default_scheme() == 'posix_local':
1610
local_path = os.path.join(home_dir, 'local')
1611
if not os.path.exists(local_path):
1612
os.mkdir(local_path)
1613
for subdir_name in os.listdir(home_dir):
1614
if subdir_name == 'local':
1616
os.symlink(os.path.abspath(os.path.join(home_dir, subdir_name)), \
1617
os.path.join(local_path, subdir_name))
1619
def fix_lib64(lib_dir):
1621
Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
1622
instead of lib/pythonX.Y. If this is such a platform we'll just create a
1623
symlink so lib64 points to lib
1625
if [p for p in distutils.sysconfig.get_config_vars().values()
1626
if isinstance(p, basestring) and 'lib64' in p]:
1627
logger.debug('This system uses lib64; symlinking lib64 to lib')
1628
assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
1629
"Unexpected python lib dir: %r" % lib_dir)
1630
lib_parent = os.path.dirname(lib_dir)
1631
top_level = os.path.dirname(lib_parent)
1632
lib_dir = os.path.join(top_level, 'lib')
1633
lib64_link = os.path.join(top_level, 'lib64')
1634
assert os.path.basename(lib_parent) == 'lib', (
1635
"Unexpected parent dir: %r" % lib_parent)
1636
if os.path.lexists(lib64_link):
1638
os.symlink('lib', lib64_link)
1640
def resolve_interpreter(exe):
1642
If the executable given isn't an absolute path, search $PATH for the interpreter
1644
if os.path.abspath(exe) != exe:
1645
paths = os.environ.get('PATH', '').split(os.pathsep)
1647
if os.path.exists(os.path.join(path, exe)):
1648
exe = os.path.join(path, exe)
1650
if not os.path.exists(exe):
1651
logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
1653
if not is_executable(exe):
1654
logger.fatal('The executable %s (from --python=%s) is not executable' % (exe, exe))
1658
def is_executable(exe):
1659
"""Checks a file is executable"""
1660
return os.access(exe, os.X_OK)
1662
############################################################
1663
## Relocating the environment:
1665
def make_environment_relocatable(home_dir):
1667
Makes the already-existing environment use relative paths, and takes out
1668
the #!-based environment selection in scripts.
1670
home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
1671
activate_this = os.path.join(bin_dir, 'activate_this.py')
1672
if not os.path.exists(activate_this):
1674
'The environment doesn\'t have a file %s -- please re-run virtualenv '
1675
'on this environment to update it' % activate_this)
1676
fixup_scripts(home_dir)
1677
fixup_pth_and_egg_link(home_dir)
1678
## FIXME: need to fix up distutils.cfg
1680
OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
1681
'activate', 'activate.bat', 'activate_this.py']
1683
def fixup_scripts(home_dir):
1684
# This is what we expect at the top of scripts:
1685
shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
1686
# This is what we'll put:
1687
new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
1689
bin_suffix = 'Scripts'
1692
bin_dir = os.path.join(home_dir, bin_suffix)
1693
home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
1694
for filename in os.listdir(bin_dir):
1695
filename = os.path.join(bin_dir, filename)
1696
if not os.path.isfile(filename):
1697
# ignore subdirs, e.g. .svn ones.
1699
f = open(filename, 'rb')
1702
lines = f.read().decode('utf-8').splitlines()
1703
except UnicodeDecodeError:
1704
# This is probably a binary program instead
1705
# of a script, so just ignore it.
1710
logger.warn('Script %s is an empty file' % filename)
1712
if not lines[0].strip().startswith(shebang):
1713
if os.path.basename(filename) in OK_ABS_SCRIPTS:
1714
logger.debug('Cannot make script %s relative' % filename)
1715
elif lines[0].strip() == new_shebang:
1716
logger.info('Script %s has already been made relative' % filename)
1718
logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
1719
% (filename, shebang))
1721
logger.notify('Making script %s relative' % filename)
1722
script = relative_script([new_shebang] + lines[1:])
1723
f = open(filename, 'wb')
1724
f.write('\n'.join(script).encode('utf-8'))
1727
def relative_script(lines):
1728
"Return a script that'll work in a relocatable environment."
1729
activate = "import os; activate_this=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this"
1730
# Find the last future statement in the script. If we insert the activation
1731
# line before a future statement, Python will raise a SyntaxError.
1733
for idx, line in reversed(list(enumerate(lines))):
1734
if line.split()[:3] == ['from', '__future__', 'import']:
1735
activate_at = idx + 1
1737
if activate_at is None:
1738
# Activate after the shebang.
1740
return lines[:activate_at] + ['', activate, ''] + lines[activate_at:]
1742
def fixup_pth_and_egg_link(home_dir, sys_path=None):
1743
"""Makes .pth and .egg-link files use relative paths"""
1744
home_dir = os.path.normcase(os.path.abspath(home_dir))
1745
if sys_path is None:
1747
for path in sys_path:
1750
if not os.path.isdir(path):
1752
path = os.path.normcase(os.path.abspath(path))
1753
if not path.startswith(home_dir):
1754
logger.debug('Skipping system (non-environment) directory %s' % path)
1756
for filename in os.listdir(path):
1757
filename = os.path.join(path, filename)
1758
if filename.endswith('.pth'):
1759
if not os.access(filename, os.W_OK):
1760
logger.warn('Cannot write .pth file %s, skipping' % filename)
1762
fixup_pth_file(filename)
1763
if filename.endswith('.egg-link'):
1764
if not os.access(filename, os.W_OK):
1765
logger.warn('Cannot write .egg-link file %s, skipping' % filename)
1767
fixup_egg_link(filename)
1769
def fixup_pth_file(filename):
1773
prev_lines = f.readlines()
1775
for line in prev_lines:
1777
if (not line or line.startswith('#') or line.startswith('import ')
1778
or os.path.abspath(line) != line):
1781
new_value = make_relative_path(filename, line)
1782
if line != new_value:
1783
logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
1784
lines.append(new_value)
1785
if lines == prev_lines:
1786
logger.info('No changes to .pth file %s' % filename)
1788
logger.notify('Making paths in .pth file %s relative' % filename)
1789
f = open(filename, 'w')
1790
f.write('\n'.join(lines) + '\n')
1793
def fixup_egg_link(filename):
1795
link = f.readline().strip()
1797
if os.path.abspath(link) != link:
1798
logger.debug('Link in %s already relative' % filename)
1800
new_link = make_relative_path(filename, link)
1801
logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
1802
f = open(filename, 'w')
1806
def make_relative_path(source, dest, dest_is_directory=True):
1808
Make a filename relative, where the filename is dest, and it is
1809
being referred to from the filename source.
1811
>>> make_relative_path('/usr/share/something/a-file.pth',
1812
... '/usr/share/another-place/src/Directory')
1813
'../another-place/src/Directory'
1814
>>> make_relative_path('/usr/share/something/a-file.pth',
1815
... '/home/user/src/Directory')
1816
'../../../home/user/src/Directory'
1817
>>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
1820
source = os.path.dirname(source)
1821
if not dest_is_directory:
1822
dest_filename = os.path.basename(dest)
1823
dest = os.path.dirname(dest)
1824
dest = os.path.normpath(os.path.abspath(dest))
1825
source = os.path.normpath(os.path.abspath(source))
1826
dest_parts = dest.strip(os.path.sep).split(os.path.sep)
1827
source_parts = source.strip(os.path.sep).split(os.path.sep)
1828
while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
1831
full_parts = ['..']*len(source_parts) + dest_parts
1832
if not dest_is_directory:
1833
full_parts.append(dest_filename)
1835
# Special case for the current directory (otherwise it'd be '')
1837
return os.path.sep.join(full_parts)
1841
############################################################
1842
## Bootstrap script creation:
1844
def create_bootstrap_script(extra_text, python_version=''):
1846
Creates a bootstrap script, which is like this script but with
1847
extend_parser, adjust_options, and after_install hooks.
1849
This returns a string that (written to disk of course) can be used
1850
as a bootstrap script with your own customizations. The script
1851
will be the standard virtualenv.py script, with your extra text
1852
added (your extra text should be Python code).
1854
If you include these functions, they will be called:
1856
``extend_parser(optparse_parser)``:
1857
You can add or remove options from the parser here.
1859
``adjust_options(options, args)``:
1860
You can change options here, or change the args (if you accept
1861
different kinds of arguments, be sure you modify ``args`` so it is
1862
only ``[DEST_DIR]``).
1864
``after_install(options, home_dir)``:
1866
After everything is installed, this function is called. This
1867
is probably the function you are most likely to use. An
1870
def after_install(options, home_dir):
1871
subprocess.call([join(home_dir, 'bin', 'easy_install'),
1873
subprocess.call([join(home_dir, 'bin', 'my-package-script'),
1876
This example immediately installs a package, and runs a setup
1877
script from that package.
1879
If you provide something like ``python_version='2.5'`` then the
1880
script will start with ``#!/usr/bin/env python2.5`` instead of
1881
``#!/usr/bin/env python``. You can use this when the script must
1882
be run with a particular Python version.
1885
if filename.endswith('.pyc'):
1886
filename = filename[:-1]
1887
f = codecs.open(filename, 'r', encoding='utf-8')
1890
py_exe = 'python%s' % python_version
1891
content = (('#!/usr/bin/env %s\n' % py_exe)
1892
+ '## WARNING: This file is generated\n'
1894
return content.replace('##EXT' 'END##', extra_text)
1899
b = base64.b64decode(s.encode('ascii'))
1900
return zlib.decompress(b).decode('utf-8')
1903
SITE_PY = convert("""
1904
eJzFPf1z2zaWv/OvwMqToeTKdOJ0eztO3RsncVrfuYm3SWdz63q0lARZrCmSJUjL6s3d337vAwAB
1905
kpLtTXdO04klEnh4eHhfeHgPHQwGp0Uhs7lY5fM6lULJuJwtRRFXSyUWeSmqZVLOD4q4rDbwdHYb
1906
30glqlyojYqwVRQE+1/4CfbFp2WiDArwLa6rfBVXySxO041IVkVeVnIu5nWZZDciyZIqidPkd2iR
1907
Z5HY/3IMgvNMwMzTRJbiTpYK4CqRL8TlplrmmRjWBc75RfTn+OVoLNSsTIoKGpQaZ6DIMq6CTMo5
1908
oAktawWkTCp5oAo5SxbJzDZc53U6F0Uaz6T4xz94atQ0DAOVr+R6KUspMkAGYEqAVSAe8DUpxSyf
1909
y0iI13IW4wD8vCFWwNDGuGYKyZjlIs2zG5hTJmdSqbjciOG0rggQoSzmOeCUAAZVkqbBOi9v1QiW
1910
lNZjDY9EzOzhT4bZA+aJ43c5B3D8kAU/Z8n9mGED9yC4aslsU8pFci9iBAs/5b2cTfSzYbIQ82Sx
1911
ABpk1QibBIyAEmkyPSxoOb7VK/TdIWFluTKGMSSizI35JfWIgvNKxKkCtq0LpJEizN/KaRJnQI3s
1912
DoYDiEDSoG+ceaIqOw7NTuQAoMR1rEBKVkoMV3GSAbP+GM8I7b8l2TxfqxFRAFZLiV9rVbnzH/YQ
1913
AFo7BBgHuFhmNessTW5luhkBAp8A+1KqOq1QIOZJKWdVXiZSEQBAbSPkPSA9FnEpNQmZM43cjon+
1914
RJMkw4VFAUOBx5dIkkVyU5ckYWKRAOcCV7z78JN4e/b6/PS95jEDjGX2ZgU4AxRaaAcnGEAc1qo8
1915
THMQ6Ci4wD8ins9RyG5wfMCraXD44EoHQ5h7EbX7OAsOZNeLq4eBOVagTGisgPr9N3QZqyXQ538e
1916
WO8gON1GFZo4f1svc5DJLF5JsYyZv5Azgm81nO+iolq+Am5QCKcCUilcHEQwQXhAEpdmwzyTogAW
1917
S5NMjgKg0JTa+qsIrPA+zw5orVucABDKIIOXzrMRjZhJmGgX1ivUF6bxhmammwR2nVd5SYoD+D+b
1918
kS5K4+yWcFTEUPxtKm+SLEOEkBeCcC+kgdVtApw4j8QFtSK9YBqJkLUXt0SRqIGXkOmAJ+V9vCpS
1919
OWbxRd26W43QYLISZq1T5jhoWZF6pVVrptrLe0fR5xbXEZrVspQAvJ56QrfI87GYgs4mbIp4xeJV
1920
rXPinKBHnqgT8gS1hL74HSh6qlS9kvYl8gpoFmKoYJGnab4Gkh0HgRB72MgYZZ854S28g38BLv6b
1921
ymq2DAJnJAtYg0Lkt4FCIGASZKa5WiPhcZtm5baSSTLWFHk5lyUN9ThiHzLij2yMcw3e55U2ajxd
1922
XOV8lVSokqbaZCZs8bKwYv34iucN0wDLrYhmpmlDpxVOLy2W8VQal2QqFygJepFe2WWHMYOeMckW
1923
V2LFVgbeAVlkwhakX7Gg0llUkpwAgMHCF2dJUafUSCGDiRgGWhUEfxWjSc+1swTszWY5QIXE5nsG
1924
9gdw+x3EaL1MgD4zgAAaBrUULN80qUp0EBp9FPhG3/Tn8YFTzxfaNvGQizhJtZWPs+CcHp6VJYnv
1925
TBbYa6yJoWCGWYWu3U0GdEQxHwwGQWDcoY0yX3MVVOXmGFhBmHEmk2mdoOGbTNDU6x8q4FGEM7DX
1926
zbaz8EBDmE7vgUpOl0WZr/C1ndtHUCYwFvYI9sQlaRnJDrLHia+QfK5KL0xTtN0OOwvUQ8HlT2fv
1927
zj+ffRQn4qpRaeO2PruGMc+yGNiaLAIwVWvYRpdBS1R8Ceo+8Q7MOzEF2DPqTeIr46oG3gXUP5U1
1928
vYZpzLyXwdn709cXZ5OfP579NPl4/ukMEAQ7I4M9mjKaxxocRhWBcABXzlWk7WvQ6UEPXp9+tA+C
1929
SaImxabYwAMwlMDC5RDmOxYhPpxoGzxJskUejqjxr+yEn7Ba0R7X1fHX1+LkRIS/xndxGIDX0zTl
1930
RfyRBODTppDQtYI/w1yNgmAuFyAstxJFarhPnuyIOwARoWWuLeuveZKZ98xH7hAk8UPqAThMJrM0
1931
VgobTyYhkJY69HygQ8TuMMrJEDoWG7frSKOCn1LCUmTYZYz/9KAYT6kfosEoul1MIxCw1SxWklvR
1932
9KHfZIJaZjIZ6gFB/IjHwUVixREK0wS1TJmAJ0q8glpnqvIUfyJ8lFsSGdwMoV7DRdKbneguTmup
1933
hs6kgIjDYYuMqBoTRRwETsUQbGezdKNRm5qGZ6AZkC/NQe+VLcrhZw88FFAwZtuFWzPeLTHNENP/
1934
4L0B4QBOYogKWqkWFNZn4vLsUrx8fnSADgjsEueWOl5ztKlJVkv7cAGrdSMrB2HuFY5JGEYuXRao
1935
GfHp8W6Yq8iuTJcVFnqJS7nK7+QcsEUGdlZZ/ERvYC8N85jFsIqgicmCs9Iznl6MO0eePUgLWnug
1936
3oqgmPU3S7/H23eZKVAdvBUmUut9OhuvoszvEnQPphv9EqwbqDe0ccYVCZyF85gMjRhoCPBbM6TU
1937
WoagwMqaXUzCG0Gihp83qjAicBeoW6/p622Wr7MJ711PUE0OR5Z1UbA082KDZgn2xDuwG4BkDlux
1938
hmgMBZx0gbJ1AMjD9GG6QFnaDQAgMM2KNlgOLLM5oynyPg+HRRijV4KEt5Ro4e/MELQ5MsRwINHb
1939
yD4wWgIhweSsgrOqQTMZypppBgM7JPG57iLiTaMPoEXFCAzdUEPjRoZ+V8egnMWFq5ScfmhDP3/+
1940
zGyjlhQRQcSmOGk0+gsyb1GxAVOYgE4wPhTHV4gN1uCOAphaadYUBx9FXrD/BOt5qWUbLDfsx6qq
1941
OD48XK/XkY4H5OXNoVoc/vkv33zzl+esE+dz4h+YjiMtOjgWHdI79EGjb40F+s6sXIsfk8znRoI1
1942
lORHkfOI+H1fJ/NcHB+MrP5ELm4MK/5rnA9QIBMzKFMZaDtoMHqmDp5FL9VAPBNDt+1wxJ6ENqnW
1943
ivlWF3pUOdhu8DRmeZ1VoaNIlfgKrBvsqedyWt+EdnDPRpofMFWU06HlgYMX14iBzxmGr4wpnqCW
1944
ILZAi++Q/idmm5j8Ga0hkLxoojr73U2/FjPEnT9e3q136AiNmWGikDtQIvwmjxZA27grOfjRzija
1945
PccZNR/PEBhLHxjm1a7gEAWHcMG1GLtS53A1+qggTWtWzaBgXNUIChrcuilTW4MjGxkiSPRuzPac
1946
F1a3ADq1Yn1mR29WAVq443SsXZsVHE8IeeBEvKAnEpza486757y0dZpSCKbFox5VGLC30Ginc+DL
1947
oQEwFoPy5wG3NBuLD61F4TXoAZZz1AYZbNFhJnzj+oCDvUEPO3Ws/rbeTOM+ELhIQ44ePQo6oXzC
1948
I5QKpKkY+j23sbglbnewnRaHmMosE4m02iJcbeXRK1Q7DdMiyVD3OosUzdIcvGKrFYmRmve+s0A7
1949
F3zcZ8y0BGoyNORwGp2Qt+cJYKjbYcDrpsbQgBs5QYxWiSLrhmRawj/gVlBEgsJHQEuCZsE8Vsr8
1950
if0BMmfnq79sYQ9LaGQIt+k2N6RjMTQc835PIBl1/ASkIAMSdoWRXEdWBylwmLNAnnDDa7lVuglG
1951
pEDOHAtCagZwp5feBgefRHhmQRKKkO8rJQvxlRjA8rVF9XG6+w/lUhM2GDoNyFXQ8YYTNxbhxCFO
1952
WnEJn6H9iASdbhQ5cPAUXB43NO+yuWFaGyYBZ91X3BYp0MgUORmMXFSvDWHc8O+fTpwWDbHMIIah
1953
vIG8Qxgz0iiwy61Bw4IbMN6at8fSj92IBfYdhrk6kqt72P+FZaJmuQpxg9uJXbgfzRVd2lhsL5Lp
1954
AP54CzAYXXuQZKrjFxhl+ScGCT3oYR90b7IYFpnH5TrJQlJgmn4n/tJ08LCk9Izc4UfaTh3CRDFG
1955
efiuBAGhw8pDECfUBLArl6HSbn8X7M4pDixc7j7w3Oar45fXXeKOt0V47Kd/qc7uqzJWuFopLxoL
1956
Ba5W14Cj0oXJxdlGHzfq42jcJpS5gl2k+PDxs0BCcCR2HW+eNvWG4RGbB+fkfQzqoNceJFdrdsQu
1957
gAhqRWSUw/DpHPl4ZJ86uR0TewKQJzHMjkUxkDSf/DNwdi0UjHEw32QYR2urDPzA62++nvRERl0k
1958
v/l68MAoLWL0if2w5QnakSkNQPRO23QpZZySr+F0oqhi1vCObVOMWKHT/k8z2XWP06nxonhmfK+S
1959
36X4Thzt77886m+LHwMP4+ES3IXn44aC3Vnjx/estsLTJmsHsM7G1Xz2aAqwzc+nv8JmWen42l2c
1960
pHQoAGQ4OEA9a/b5HLroVyQepJ26xiFB31ZMXT0Hxgg5sDDqTkf7Zacm9tyzITafIlZdVPZ0AkBz
1961
fuUd6rtnl12oetkNDz/nk4ajHi3lzbjPr/gSDYufP0QZWWAeDQZ9ZN/Kjv8fs3z+r5nkI6dijp3/
1962
QMP4REB/1EzYjjA0bUd8WP3L7ppgA+wRlmqLB7rDQ+wOzQeNC+PnsUpSYh91175YU64BhVnx0Aig
1963
zNkF7IGDy6hPrN/UZcnnzqQCC1ke4FnqWGCalXECKXurC+bwvawQE9tsRmFrJykn71MjoQ5E25mE
1964
zRaiX86WuQlfyewuKaEvKNxh+MOHH8/CfhOCIV3o9Hgr8ngXAuE+gWlDTZzwKX2YQk/p8s9LVXsX
1965
4xPUHOeb4LAmW6998GPCJqTQvwYPBIe8s1s+I8fN+mwpZ7cTSef+yKbY1YmPv8HXiIlNB/CTt1S8
1966
oAw0mMksrZFW7INj6uCizmZ0VFJJcLV0ni/m/dBpPkcCF2l8I4bUeY5RKM2NFKi6i0vtiBZljpml
1967
ok7mhzfJXMjf6jjFHb5cLAAXPMfSryIenoJR4i0nJHDGoZKzukyqDZAgVrk+BqTcBafhdMMTHXpI
1968
8okPExCzGY7FR5w2vmfCzQ25TJzAP/zASeIWHDuYc1rkLnoO77N8gqNOKEF3zEh1j+jpcdAeIQcA
1969
AwAK8x+MdBDPfyPplXvWSGvuEhW1pEdKN+iQkzOGUIYjDHrwb/rpM6LLW1uwvNmO5c1uLG/aWN70
1970
YnnjY3mzG0tXJHBhbfzKSEJfDKt9wtGbLOOGn3iYs3i25HaYuIkJmgBRFGavbWSK85e9IBcf9REQ
1971
UtvO2TM9bJJfEs4ILXOOhmuQyP14nqX39Sbz3OlMqTS6M0/FuLPbEoD8vodRRHleU+rO8jaPqzjy
1972
5OImzacgthbdcQNgLNq5QBw2ze4mUw70tizV4PK/Pv3w4T02R1ADk+lA3XAR0bDgVIb7cXmjutLU
1973
7AMLYEdq6efkUDcNcO+RQTYeZY//eUvJHsg4Yk3JCrkowAOglCzbzE1cCsPWc53hpJ8zk/O504kY
1974
ZNWgmdQWIp1eXr49/XQ6oOjf4H8HrsAY2vrS4eJjWtgGXf/NbW4pjn1AqHWYqzF+7pw8Wjcc8bCN
1975
NWA7PnzrwdFjDHZvxMCf5b+UUrAkQKhIx4GfQqhH74G+aJvQoY9hxE7mnnvIxs6KfefInuOiOKLf
1976
dwLRHsA/98Q9xgQIoF2oodkZNJupltK35nUHRR2gj/T1vngL1t56tXcyPkXtJHocQIeyttl29887
1977
smGjp2T1+uz78/cX568vTz/94LiA6Mp9+Hh4JM5+/CwoVQQNGPtEMWZJVJiUBIbFrVIS8xz+qzHy
1978
M68rjhdDr7cXF/rQZoV1Kpi4jDYnguec0WShcfiMA9L2oU5FQoxSvUFyCoIoc4cKhnC/tOJiFJXr
1979
5GaqM5qis1rrrZcu9DIFYXTEHYH0QWOXFAyCs83gFaWgV2ZXWPJhoC6S6kFK22ibI5JSeLCTOeAc
1980
hZmDFi9mSp3hSdNZK/qr0MU1vI5UkSawk3sVWlnS3TBTpmEc/dCedTNefRrQ6Q4j64Y8661YoNV6
1981
FfLcdP9Rw2i/1YBhw2BvYd6ZpEwRSp/GPDcRYiM+1AnlPXy1S6/XQMGC4ZlfhYtomC6B2cewuRbL
1982
BDYQwJNLsL64TwAIrZXwzwaOneiAzDFRI3yzmh/8NdQE8Vv/8ktP86pMD/4uCtgFCc4qCnuI6TZ+
1983
CxufSEbi7MO7UcjIUZau+GuNuf3gkFAA1JF2SmXiw/TJUMl0oVNNfH2AL7SfQK9b3UtZlLp7v2sc
1984
ogQ8U0PyGp4pQ78QM78s7DFOZdQCjWULFjMs/3MzEsxnT3xcyjTVyernby/OwHfESgqUID6CO4Ph
1985
OF6Cp+k6D4/LE1ug8KwdXpfIxiW6sJRvMY+8Zr1BaxQ56u2laNh1osBwt1cnClzGiXLRHuK0GZap
1986
BYiQlWEtzLIya7faIIXdNkRxlBlmicllSbmsPk8AL9PTmLdEsFfCOg0TgecD5SSrTPJimsxAj4LK
1987
BYU6BiFB4mIxInFennEMPC+VqWGCh8WmTG6WFZ5zQOeI6iew+Y+nny/O31NNwdHLxuvuYc4x7QTG
1988
nE9ygtmCGO2AL24GIHLVZNLHs/oVwkDtA3/arzhR5YQH6PTjwCL+ab/iIrITZyfIMwAFVRdt8cAN
1989
gNOtT24aWWBc7T4YP242YIOZD4ZikVizonM+3Pl1OdG2bJkSivuYl084wFkUNjtNd3az09ofPcdF
1990
gSde82F/I3jbJ1vmM4Wut5032/Lg3E9HCrGeFTDqtvbHMIlinaZ6Og6zbeMW2tZqG/tL5sRKnXaz
1991
DEUZiDh0O49cJutXwro5c6CXUd0BJr7V6BpJ7FXlg1+ygfYwPEwssTv7FNORKlrICGAkQ+rCnRp8
1992
KLQIoEAoEXjoSO54tH/kzdGxBg/PUesusI0/gCLUablU7pGXwInw5Td2HPkVoYV69FiEjqeSySy3
1993
KWP4WS/Rq3zhz7FXBiiIiWJXxtmNHDKssYH5lU/sLSFY0rYeqa+S6z7DIs7BOb3fwuFdueg/ODGo
1994
tRih0+5WbtrqyCcPNuitCtlJMB98Ga9B9xd1NeSV3HIO3VsItx3qwxAxERGa6nP4YYjhmN/CLevT
1995
AO6lhoaFHt5vW05heW2MI2vtY6vAKbQvtAc7K2FrVik6lnEqC40var2AxuCeNCZ/YJ/qnCH7u6dk
1996
zIkJWaA8uAvSm9tAN2iFEwZcucRlnwllxjeFNfrdXN7JFIwGGNkhFj78agsfRpENp/SmhH0xdpeb
1997
y00/bvSmwezYVGagZ6YKWL8ok9UhotMb8dmFWYMMLvUveksSZ7fkJb/52/lYvHn/E/z7Wn4AU4qV
1998
i2Pxd0BDvMlL2F9y6S3diYBFHRVvHPNaYXkjQaOjCr4+At22S4/OeCyiq038MhOrKQUm2JYrvrME
1999
UOQJUjl64yeYGgr4bYq8Wt6o8RT7FmWgXyINtte9YK3IoW4ZLatVivbCiZI0q3k1uDh/c/b+41lU
2000
3SOHm58DJ4ri52bhdPQZcYnnYWNhn8xqfHLtOM4/yLTo8Zv1ptPU0OCmU4SwLynsRpPvw4jt5iIu
2001
MXIgis08n0XYEliey/aqNTjSI2d/+aCh96wswhqO9Cla483jY6CG+KWtiAbQkProOVFPQiieYv0Y
2002
P44G/aZ4LCi0DX/2b9dzNzKuC4Fogm1Mm1kP/e5WFy6Zzhqe5STC68Qug6kNTZNYraYzt2bwQyb0
2003
dSag5eicQy7iOq2EzEByaZNP90qApnfL/FhCmFXYnFHtG4Vp0nW8UU4SUqzEAEcdUGk8HshQxBD2
2004
4D/Gt2wPsP5Q1FzIDNAJUdo/5U5XVc+WLMG8JSLq9SQerJPspZvPoynMg/IOedY4sjBPdBsZoxtZ
2005
6fnzg+Ho6kWT6UBR6ZlX5DsrwOq5bLIHqrPY398fiH9/2PthVKI0z2/BLQPYvV7LBb3eYrn15Oxq
2006
dT178yYCfpwt5RU8uKbouX1eZxSa3NGVFkTavwZGiGsTWmY07Vt2mYN2JR80cws+sNKW4+csoUuL
2007
MLQkUdnqu58w7GSkiVgSFEMYq1mShBymgPXY5DXW52GYUfOLvAeOTxDMGN/iCRlvtZfoYVIureUe
2008
i86JGBDgAeWW8WhU4EwVaoDn5HKj0ZycZ0nVlJY8dw9PdSF/Ze8i0nwl4jVKhplHixhOqafHqo2H
2009
ne9kUW/Hks+u3IBja5b8+iHcgbVB0vLFwmAKD80izXJZzow5xRVLZknlgDHtEA53piuYyPpEQQ9K
2010
A1DvZBXmVqLt2z/ZdXEx/UDnyAdmJJ0+VNlrrTg4FGetBMMoasanMJQlpOVb82UEo7ynsLb2BLyx
2011
xJ90UBXrCrzbN9wSxzrTt2pw/kZz1QbAoZucrIK07OjpCOf6MAufmXbLXRj4oS064XaXlFUdpxN9
2012
ecMEHbaJPVjXeNrSuJ1Fn9ZbASc/Bw/4QGfxg+NgsmyQnpiEa6o0TsRChygit9rML8wqcvTyjthX
2013
Ap8CKTOfmBppE0S6suxqi091zqaj4hHUV6agaYtnbippOkUoLuZjynMyJRBbvGiDS/tOC/HdiRi+
2014
GIs/tzZCs2KDtzIBys/m0bN56Ptk1PXq+KixM92NZwvCViAvr5883TSZ0vTCvvTzh/vqpEPcAK5A
2015
dhaJnB88U4gd4/ylUDWUZl7bOYVmjNXpezbrSRdmN+UqVJU2Ba9+3SgUR7UY/9MOYiq+tR7g4lgU
2016
WrZAtqDfJJ60kv/spWuYGKjR81cWPZdJ3+EUfsOLU+C9Jqjr6Gw9tNQZ9hZsz55cl1HyEVTTsOH4
2017
Bz2qJ4lSO0e80wqPJxuJc1n/CTwc0iUzxDRftY6F/5XMw0n72w4XO1h+8/UuPF0F01sx0bOgj61i
2018
4EVvly40C28+/UEvj2X6un6R6DhQGiEC/8/c4Uie2zFmBvNVL7nNEF7hLYl06otWJpWuJ8K7U74O
2019
C10D2o5TohasCjgn9QIPae/o0sdTRQlleBPM10cvxqYAlwHpCbyMXn6l70akbuaOAd9tHevtELzU
2020
/Y6if3OAJZXf277qbBBoWidu6uKYyu6dwUKKTI2iiaVDY0MerrFo1iwWeJlgQ0x2V+09G+/AgZiC
2021
62BuBc3BB4I9XtSHrqs7GjnepuS2ifLWOKL9bBOiR+SAuDoVsd4ld9v06C4d+mRZ0L36jQluy5H1
2022
lzG/QfeqLo5t2MqYFzxWHLqpkvipbnvru9i0oJ2tbsNd0+f+u+auWwR25iZToDN3v47TpYHuu92g
2023
9tGAQwaaEI+qP2iUf79dcU3CWCeo9Ie/9QfJ73bCmW6xMA+BMekwGEwn9tTYGw9gFc/c75htdcBX
2024
Fbtlu71+R2vaHfPR5vjHOA2cWYLPbSU/pQvNNQfyHoTunptwAupE3tyoSYz3Hk5o40rJUp0didkK
2025
vaNr62SsNmYHg5cDAQjDTTqt1c1cB8YAZcn3L3OukXMLjKChKSPXSfFVyZxtgt4uAbiIo5DU30S5
2026
OUd3kEoMHqu6LErYYQ70Lb2cBNOXN9wANUGxVaxuDeqmx1hf2kqalTKvTKkvxz5ZzXrUAUKwJe/Y
2027
h8nEvgN+ed5caZCMLUPIrF7JMq6a63z8I/cEvIhmBCrwxgV2wl6NZLY4xUUssfzhIIWBJ/v9K71h
2028
8zasO+4xGFmt93i2oh46nPqUKxIcq2S4Obm31/m510jN6fJn12G0zRrus1cYwVKYu+lIV+o4FL/V
2029
92XxLawcJUeX0+EjkHu3vNFP9bZqjR1ei4bzzFUM3QuSsEKfrHTfvYcdLujecNjatNrxfb1hmaXj
2030
am5pbKmo3fRexdOMNmqiM5iV+UB0xs+8f2J0xoP/yOiMvqUSDI7GR+uD3lz8B8I4rCbcKx8bRoA+
2031
EyASnhK3Lgw0JnPoZrYXuUruB/bKZdaZTrmcMRPIkd27wAgEX+2o3DRg7+q1XdEZX7ro8fcXH16f
2032
XhAtJpenb/7z9HvKfMKjiJbNenT4KssPmNoHXo61G8rS2Sp9gzfY9tyhyoVCGkLnfeegvwdCf1FY
2033
34K2FZn7eluHTnFNtxMgvnvaLajbVHYv5I5/pgs53ByVVjJ0oJ9y5qr55Rz/m0fmFIzFoTnlMu+b
2034
gwkto5247baFc3JIu+pE+6361s0tMeWRzWSmFcDzCOQvexxhylJs0Jsdlfb/CIPSr7Gkz9xYA1I4
2035
k87NiXRpIoOq/P/jRgnKLsZNHjuMY3t7NbXjoxdlr2XHc9WZjAxBvJq6QXd+rrDPZbqFCkHACk/f
2036
C8iIGP2nDyvt0f4zJa4OqHr3AJXNtf2Fa6ad3L8leIBf2fu1FGcB8REmNF7UqXsob/t0OpDzRyc9
2037
+cIpFwHNdwh0bsRTAXujz8QKcboRIWwg9eEzZqASHfXleA7yaDcd7A2tnouDbbWdbm2jEC+2N5y3
2038
yid1jyPuoR7ooWpTQedYYEyF3Fa0Kb4jyHxUKOhCLc/5wPNpvf+Hr3dXL45t4B75HV87ioRStgaO
2039
Yb9yUh53XuLodCdmKceUE4d7NqfkV7e4dqCyT7Btj9Op+9iyDzI5BAxp4L3vj52ZHt7l9IM2ppb1
2040
jmFKYvhMjWhaTqWMxt0+GXWn26itLhCu+nkEkI4KBFgIpqMbnSzMDadSD5/rXeG0putv3dOb0JEK
2041
ysjyOYJ7GN+vwa/dnap1H9WdUTT9uUGbA/WSg3Cz78CtRl5IZLtJaE+94YMtLgAXPvf3f/GI/t1c
2042
Qdv9aJdfbVu97C22Y18W00sx66ZFIvM4AiMDenNI2hprEoyg410vDR1dhmrmhnyBjh+lrOLl1rTB
2043
IGd2oj0AaxSC/wPOBKoy
2047
EZ_SETUP_PY = convert("""
2048
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
2117
##file distribute_from_egg.py
2118
DISTRIBUTE_FROM_EGG_PY = convert("""
2119
eJw9j8tqAzEMRfcG/4MgmxQyptkGusonZBmGoGTUGYFfWPKE6dfXTkM3gqt7rh47OKP3NMF3SQFW
2120
LlrRU1zhybpAxoKBlIqcrNnBdRjQP3GTocYfzmNrrCPQPN9iwzpxSQfQhWBi0cL3qtRtYIG/4Mv0
2121
KApY5hooqrOGQ05FQTaxptF9Fnx16Rq0XofjaE1XGXVxHIWK7j8P8EY/rHndLqQ1a0pe3COFgHFy
2122
hLLdWkDbi/DeEpCjNb3u/zccT2Ob8gtnwVyI
2125
##file distribute_setup.py
2126
DISTRIBUTE_SETUP_PY = convert("""
2127
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
2217
ACTIVATE_SH = convert("""
2218
eJytVVFvokAQfudXTLEPtTlLeo9tvMSmJpq02hSvl7u2wRUG2QR2DSxSe7n/frOACEVNLlceRHa+
2219
nfl25pvZDswCnoDPQ4QoTRQsENIEPci4CsBMZBq7CAsuLOYqvmYKTTj3YxnBgiXBudGBjUzBZUJI
2220
BXEqgCvweIyuCjeG4eF2F5x14bcB9KQiQQWrjSddI1/oQIx6SYYeoFjzWIoIhYI1izlbhJjkKO7D
2221
M/QEmKfO9O7WeRo/zr4P7pyHwWxkwitcgwpQ5Ej96OX+PmiFwLeVjFUOrNYKaq1Nud3nR2n8nI2m
2222
k9H0friPTGVsUdptaxGrTEfpNVFEskxpXtUkkCkl1UNF9cgLBkx48J4EXyALuBtAwNYIjF5kcmUU
2223
abMKmMq1ULoiRbgsDEkTSsKSGFCJ6Z8vY/2xYiSacmtyAfCDdCNTVZoVF8vSTQOoEwSnOrngBkws
2224
MYGMBMg8/bMBLSYKS7pYEXP0PqT+ZmBT0Xuy+Pplj5yn4aM9nk72JD8/Wi+Gr98sD9eWSMOwkapD
2225
BbUv91XSvmyVkICt2tmXR4tWmrcUCsjWOpw87YidEC8i0gdTSOFhouJUNxR+4NYBG0MftoCTD9F7
2226
2rTtxG3oPwY1b2HncYwhrlmj6Wq924xtGDWqfdNxap+OYxplEurnMVo9RWks+rH8qKEtx7kZT5zJ
2227
4H7oOFclrN6uFe+d+nW2aIUsSgs/42EIPuOhXq+jEo3S6tX6w2ilNkDnIpHCWdEQhFgwj9pkk7FN
2228
l/y5eQvRSIQ5+TrL05lewxWpt/Lbhes5cJF3mLET1MGhcKCF+40tNWnUulxrpojwDo2sObdje3Bz
2229
N3QeHqf3D7OjEXMVV8LN3ZlvuzoWHqiUcNKHtwNd0IbvPGKYYM31nPKCgkUILw3KL+Y8l7aO1ArS
2230
Ad37nIU0fCj5NE5gQCuC5sOSu+UdI2NeXg/lFkQIlFpdWVaWZRfvqGiirC9o6liJ9FXGYrSY9mI1
2231
D/Ncozgn13vJvsznr7DnkJWXsyMH7e42ljdJ+aqNDF1bFnKWFLdj31xtaJYK6EXFgqmV/ymD/ROG
2232
+n8O9H8f5vsGOWXsL1+1k3g=
2235
##file activate.fish
2236
ACTIVATE_FISH = convert("""
2237
eJyVVWFv2jAQ/c6vuBoqQVWC9nVSNVGVCaS2VC2rNLWVZZILWAs2s52wVvvxsyEJDrjbmgpK7PP5
2238
3bt3d22YLbmGlGcIq1wbmCPkGhPYcLMEEsGciwGLDS+YwSjlekngLFVyBe73GXSXxqw/DwbuTS8x
2239
yyKpFr1WG15lDjETQhpQuQBuIOEKY5O9tlppLqxHKSDByjVAPwEy+mXtCq5MzjIUBTCRgEKTKwFG
2240
gpBqxTLYXgN2myspVigMaYF92tZSowGZJf4mFExxNs9Qb614CgZtmH0BpEOn11f0cXI/+za8pnfD
2241
2ZjA1sg9zlV/8QvcMhxbNu0QwgYokn/d+n02nt6Opzcjcnx1vXcIoN74O4ymWQXmHURfJw9jenc/
2242
vbmb0enj6P5+cuVhqlKm3S0u2XRtRbA2QQAhV7VhBF0rsgUX9Ur1rBUXJgVSy8O751k8mzY5OrKH
2243
RW3eaQhYGTr8hrXO59ALhxQ83mCsDLAid3T72CCSdJhaFE+fXgicXAARUiR2WeVO37gH3oYHzFKo
2244
9k7CaPZ1UeNwH1tWuXA4uFKYYcEa8vaKqXl7q1UpygMPhFLvlVKyNzsSM3S2km7UBOl4xweUXk5u
2245
6e3wZmQ9leY1XE/Ili670tr9g/5POBBpGIJXCCF79L1siarl/dbESa8mD8PL61GpzqpzuMS7tqeB
2246
1YkALrRBloBMbR9yLcVx7frQAgUqR7NZIuzkEu110gbNit1enNs82Rx5utq7Z3prU78HFRgulqNC
2247
OTwbqJa9vkJFclQgZSjbKeBgSsUtCtt9D8OwAbIVJuewQdfvQRaoFE9wd1TmCuRG7OgJ1bVXGHc7
2248
z5WDL/WW36v2oi37CyVBak61+yPBA9C1qqGxzKQqZ0oPuocU9hpud0PIp8sDHkXR1HKkNlzjuUWA
2249
a0enFUyzOWZA4yXGP+ZMI3Tdt2OuqU/SO4q64526cPE0A7ZyW2PMbWZiZ5HamIZ2RcCKLXhcDl2b
2250
vXL+eccQoRzem80mekPDEiyiWK4GWqZmwxQOmPM0eIfgp1P9cqrBsewR2p/DPMtt+pfcYM+Ls2uh
2251
hALufTAdmGl8B1H3VPd2af8fQAc4PgqjlIBL9cGQqNpXaAwe3LrtVn8AkZTUxg==
2255
ACTIVATE_CSH = convert("""
2256
eJx9VG1P2zAQ/u5fcYQKNgTNPtN1WxlIQ4KCUEGaxuQ6yYVYSuzKdhqVX7+zk3bpy5YPUXL3PPfc
2257
ne98DLNCWshliVDV1kGCUFvMoJGugMjq2qQIiVSxSJ1cCofD1BYRnOVGV0CfZ0N2DD91DalQSjsw
2258
tQLpIJMGU1euvPe7QeJlkKzgWixlhnAt4aoUVsLnLBiy5NtbJWQ5THX1ZciYKKWwkOFaE04dUm6D
2259
r/zh7pq/3D7Nnid3/HEy+wFHY/gEJydg0aFaQrBFgz1c5DG1IhTs+UZgsBC2GMFBlaeH+8dZXwcW
2260
VPvCjXdlAvCfQsE7al0+07XjZvrSCUevR5dnkVeKlFYZmUztG4BdzL2u9KyLVabTU0bdfg7a0hgs
2261
cSmUg6UwUiQl2iHrcbcVGNvPCiLOe7+cRwG13z9qRGgx2z6DHjfm/Op2yqeT+xvOLzs0PTKHDz2V
2262
tkckFHoQfQRXoGJAj9el0FyJCmEMhzgMS4sB7KPOE2ExoLcSieYwDvR+cP8cg11gKkVJc2wRcm1g
2263
QhYFlXiTaTfO2ki0fQoiFM4tLuO4aZrhOzqR4dIPcWx17hphMBY+Srwh7RTyN83XOWkcSPh1Pg/k
2264
TXX/jbJTbMtUmcxZ+/bbqOsy82suFQg/BhdSOTRhMNBHlUarCpU7JzBhmkKmRejKOQzayQe6MWoa
2265
n1wqWmuh6LZAaHxcdeqIlVLhIBJdO9/kbl0It2oEXQj+eGjJOuvOIR/YGRqvFhttUB2XTvLXYN2H
2266
37CBdbW2W7j2r2+VsCn0doVWcFG1/4y1VwBjfwAyoZhD
2270
ACTIVATE_BAT = convert("""
2271
eJx9UdEKgjAUfW6wfxjiIH+hEDKUFHSKLCMI7kNOEkIf9P9pTJ3OLJ/03HPPPed4Es9XS9qqwqgT
2272
PbGKKOdXL4aAFS7A4gvAwgijuiKlqOpGlATS2NeMLE+TjJM9RkQ+SmqAXLrBo1LLIeLdiWlD6jZt
2273
r7VNubWkndkXaxg5GO3UaOOKS6drO3luDDiO5my3iA0YAKGzPRV1ack8cOdhysI0CYzIPzjSiH5X
2274
0QcvC8Lfaj0emsVKYF2rhL5L3fCkVjV76kShi59NHwDniAHzkgDgqBcwOgTMx+gDQQqXCw==
2277
##file deactivate.bat
2278
DEACTIVATE_BAT = convert("""
2279
eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgUliIit
2280
KhZlqkpcnCA1WKRsuTTxWBIZ4uHv5+Hv64piEVwU3TK4BNBCmHIcKvDb6xjigWIjkI9uF1AIu7dA
2281
akGGW7n6uXABALCXXUI=
2285
ACTIVATE_PS = convert("""
2286
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
2375
##file distutils-init.py
2376
DISTUTILS_INIT = convert("""
2377
eJytV1uL4zYUfvevOE0ottuMW9q3gVDa3aUMXXbLMlDKMBiNrSTqOJKRlMxkf33PkXyRbGe7Dw2E
2378
UXTu37lpxLFV2oIyifAncxmOL0xLIfcG+gv80x9VW6maw7o/CANSWWBwFtqeWMPlGY6qPjV8A0bB
2379
C4eKSTgZ5LRgFeyErMEeOBhbN+Ipgeizhjtnhkn7DdyjuNLPoCS0l/ayQTG0djwZC08cLXozeMss
2380
aG5EzQ0IScpnWtHSTXuxByV/QCmxE7y+eS0uxWeoheaVVfqSJHiU7Mhhi6gULbOHorshkrEnKxpT
2381
0n3A8Y8SMpuwZx6aoix3ouFlmW8gHRSkeSJ2g7hU+kiHLDaQw3bmRDaTGfTnty7gPm0FHbIBg9U9
2382
oh1kZzAFLaue2R6htPCtAda2nGlDSUJ4PZBgCJBGVcwKTAMz/vJiLD+Oin5Z5QlvDPdulC6EsiyE
2383
NFzb7McNTKJzbJqzphx92VKRFY1idenzmq3K0emRcbWBD0ryqc4NZGmKOOOX9Pz5x+/l27tP797c
2384
f/z0d+4NruGNai8uAM0bfsYaw8itFk8ny41jsfpyO+BWlpqfhcG4yxLdi/0tQqoT4a8Vby382mt8
2385
p7XSo7aWGdPBc+b6utaBmCQ7rQKQoWtAuthQCiold2KfJIPTT8xwg9blPumc+YDZC/wYGdAyHpJk
2386
vUbHbHWAp5No6pK/WhhLEWrFjUwtPEv1Agf8YmnsuXUQYkeZoHm8ogP16gt2uHoxcEMdf2C6pmbw
2387
hUMsWGhanboh4IzzmsIpWs134jVPqD/c74bZHdY69UKKSn/+KfVhxLgUlToemayLMYQOqfEC61bh
2388
cbhwaqoGUzIyZRFHPmau5juaWqwRn3mpWmoEA5nhzS5gog/5jbcFQqOZvmBasZtwYlG93k5GEiyw
2389
buHhMWLjDarEGpMGB2LFs5nIJkhp/nUmZneFaRth++lieJtHepIvKgx6PJqIlD9X2j6pG1i9x3pZ
2390
5bHuCPFiirGHeO7McvoXkz786GaKVzC9DSpnOxJdc4xm6NSVq7lNEnKdVlnpu9BNYoKX2Iq3wvgh
2391
gGEUM66kK6j4NiyoneuPLSwaCWDxczgaolEWpiMyDVDb7dNuLAbriL8ig8mmeju31oNvQdpnvEPC
2392
1vAXbWacGRVrGt/uXN/gU0CDDwgooKRrHfTBb1/s9lYZ8ZqOBU0yLvpuP6+K9hLFsvIjeNhBi0KL
2393
MlOuWRn3FRwx5oHXjl0YImUx0+gLzjGchrgzca026ETmYJzPD+IpuKzNi8AFn048Thd63OdD86M6
2394
84zE8yQm0VqXdbbgvub2pKVnS76icBGdeTHHXTKspUmr4NYo/furFLKiMdQzFjHJNcdAnMhltBJK
2395
0/IKX3DVFqvPJ2dLE7bDBkH0l/PJ29074+F0CsGYOxsb7U3myTUncYfXqnLLfa6sJybX4g+hmcjO
2396
kMRBfA1JellfRRKJcyRpxdS4rIl6FdmQCWjo/o9Qz7yKffoP4JHjOvABcRn4CZIT2RH4jnxmfpVG
2397
qgLaAvQBNfuO6X0/Ux02nb4FKx3vgP+XnkX0QW9pLy/NsXgdN24dD3LxO2Nwil7Zlc1dqtP3d7/h
2398
kzp1/+7hGBuY4pk0XD/0Ao/oTe/XGrfyM773aB7iUhgkpy+dwAMalxMP0DrBcsVw/6p25+/hobP9
2399
GBknrWExDhLJ1bwt1NcCNblaFbMKCyvmX0PeRaQ=
2402
##file distutils.cfg
2403
DISTUTILS_CFG = convert("""
2404
eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
2405
xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
2406
9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
2409
##file activate_this.py
2410
ACTIVATE_THIS = convert("""
2411
eJyNU01v2zAMvetXEB4K21jmDOstQA4dMGCHbeihlyEIDMWmG62yJEiKE//7kXKdpN2KzYBt8euR
2412
fKSyLPs8wiEo8wh4wqZTGou4V6Hm0wJa1cSiTkJdr8+GsoTRHuCotBayiWqQEYGtMCgfD1KjGYBe
2413
5a3p0cRKiAe2NtLADikftnDco0ko/SFEVgEZ8aRC5GLux7i3BpSJ6J1H+i7A2CjiHq9z7JRZuuQq
2414
siwTIvpxJYCeuWaBpwZdhB+yxy/eWz+ZvVSU8C4E9FFZkyxFsvCT/ZzL8gcz9aXVE14Yyp2M+2W0
2415
y7n5mp0qN+avKXvbsyyzUqjeWR8hjGE+2iCE1W1tQ82hsCZN9UzlJr+/e/iab8WfqsmPI6pWeUPd
2416
FrMsd4H/55poeO9n54COhUs+sZNEzNtg/wanpjpuqHJaxs76HtZryI/K3H7KJ/KDIhqcbJ7kI4ar
2417
XL+sMgXnX0D+Te2Iy5xdP8yueSlQB/x/ED2BTAtyE3K4SYUN6AMNfbO63f4lBW3bUJPbTL+mjSxS
2418
PyRfJkZRgj+VbFv+EzHFi5pKwUEepa4JslMnwkowSRCXI+m5XvEOvtuBrxHdhLalG0JofYBok6qj
2419
YdN2dEngUlbC4PG60M1WEN0piu7Nq7on0mgyyUw3iV1etLo6r/81biWdQ9MWHFaePWZYaq+nmp+t
2420
s3az+sj7eA0jfgPfeoN1
2423
MH_MAGIC = 0xfeedface
2424
MH_CIGAM = 0xcefaedfe
2425
MH_MAGIC_64 = 0xfeedfacf
2426
MH_CIGAM_64 = 0xcffaedfe
2427
FAT_MAGIC = 0xcafebabe
2431
maxint = majver == 3 and getattr(sys, 'maxsize') or getattr(sys, 'maxint')
2434
class fileview(object):
2436
A proxy for file-like objects that exposes a given view of a file.
2437
Modified from macholib.
2440
def __init__(self, fileobj, start=0, size=maxint):
2441
if isinstance(fileobj, fileview):
2442
self._fileobj = fileobj._fileobj
2444
self._fileobj = fileobj
2446
self._end = start + size
2450
return '<fileview [%d, %d] %r>' % (
2451
self._start, self._end, self._fileobj)
2456
def _checkwindow(self, seekto, op):
2457
if not (self._start <= seekto <= self._end):
2458
raise IOError("%s to offset %d is outside window [%d, %d]" % (
2459
op, seekto, self._start, self._end))
2461
def seek(self, offset, whence=0):
2463
if whence == os.SEEK_SET:
2464
seekto += self._start
2465
elif whence == os.SEEK_CUR:
2466
seekto += self._start + self._pos
2467
elif whence == os.SEEK_END:
2470
raise IOError("Invalid whence argument to seek: %r" % (whence,))
2471
self._checkwindow(seekto, 'seek')
2472
self._fileobj.seek(seekto)
2473
self._pos = seekto - self._start
2475
def write(self, bytes):
2476
here = self._start + self._pos
2477
self._checkwindow(here, 'write')
2478
self._checkwindow(here + len(bytes), 'write')
2479
self._fileobj.seek(here, os.SEEK_SET)
2480
self._fileobj.write(bytes)
2481
self._pos += len(bytes)
2483
def read(self, size=maxint):
2485
here = self._start + self._pos
2486
self._checkwindow(here, 'read')
2487
size = min(size, self._end - here)
2488
self._fileobj.seek(here, os.SEEK_SET)
2489
bytes = self._fileobj.read(size)
2490
self._pos += len(bytes)
2494
def read_data(file, endian, num=1):
2496
Read a given number of 32-bits unsigned integers from the given file
2497
with the given endianness.
2499
res = struct.unpack(endian + 'L' * num, file.read(num * 4))
2505
def mach_o_change(path, what, value):
2507
Replace a given name (what) in any LC_LOAD_DYLIB command found in
2508
the given binary with a new name (value), provided it's shorter.
2511
def do_macho(file, bits, endian):
2512
# Read Mach-O header (the magic number is assumed read by the caller)
2513
cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = read_data(file, endian, 6)
2514
# 64-bits header has one more field.
2516
read_data(file, endian)
2517
# The header is followed by ncmds commands
2518
for n in range(ncmds):
2520
# Read command header
2521
cmd, cmdsize = read_data(file, endian, 2)
2522
if cmd == LC_LOAD_DYLIB:
2523
# The first data field in LC_LOAD_DYLIB commands is the
2524
# offset of the name, starting from the beginning of the
2526
name_offset = read_data(file, endian)
2527
file.seek(where + name_offset, os.SEEK_SET)
2528
# Read the NUL terminated string
2529
load = file.read(cmdsize - name_offset).decode()
2530
load = load[:load.index('\0')]
2531
# If the string is what is being replaced, overwrite it.
2533
file.seek(where + name_offset, os.SEEK_SET)
2534
file.write(value.encode() + '\0'.encode())
2535
# Seek to the next command
2536
file.seek(where + cmdsize, os.SEEK_SET)
2538
def do_file(file, offset=0, size=maxint):
2539
file = fileview(file, offset, size)
2541
magic = read_data(file, BIG_ENDIAN)
2542
if magic == FAT_MAGIC:
2543
# Fat binaries contain nfat_arch Mach-O binaries
2544
nfat_arch = read_data(file, BIG_ENDIAN)
2545
for n in range(nfat_arch):
2547
cputype, cpusubtype, offset, size, align = read_data(file, BIG_ENDIAN, 5)
2548
do_file(file, offset, size)
2549
elif magic == MH_MAGIC:
2550
do_macho(file, 32, BIG_ENDIAN)
2551
elif magic == MH_CIGAM:
2552
do_macho(file, 32, LITTLE_ENDIAN)
2553
elif magic == MH_MAGIC_64:
2554
do_macho(file, 64, BIG_ENDIAN)
2555
elif magic == MH_CIGAM_64:
2556
do_macho(file, 64, LITTLE_ENDIAN)
2558
assert(len(what) >= len(value))
2559
do_file(open(path, 'r+b'))
2562
if __name__ == '__main__':
2566
## Copy python.exe.manifest
2567
## Monkeypatch distutils.sysconfig