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.7.2" # following best practices
8
virtualenv_version = __version__ # legacy, again
21
import distutils.sysconfig
22
from distutils.util import strtobool
28
if sys.version_info <= (2, 3):
29
print('ERROR: %s' % sys.exc_info()[1])
30
print('ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.')
31
print('If you copy subprocess.py from a newer version of Python this script will probably work')
38
from sets import Set as set
47
import configparser as ConfigParser
50
py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
52
is_jython = sys.platform.startswith('java')
53
is_pypy = hasattr(sys, 'pypy_version_info')
54
is_win = (sys.platform == 'win32')
55
abiflags = getattr(sys, 'abiflags', '')
57
user_dir = os.path.expanduser('~')
58
if sys.platform == 'win32':
59
user_dir = os.environ.get('APPDATA', user_dir) # Use %APPDATA% for roaming
60
default_storage_dir = os.path.join(user_dir, 'virtualenv')
62
default_storage_dir = os.path.join(user_dir, '.virtualenv')
63
default_config_file = os.path.join(default_storage_dir, 'virtualenv.ini')
68
expected_exe = 'jython'
70
expected_exe = 'python'
73
REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
74
'fnmatch', 'locale', 'encodings', 'codecs',
75
'stat', 'UserDict', 'readline', 'copy_reg', 'types',
76
're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
79
REQUIRED_FILES = ['lib-dynload', 'config']
81
majver, minver = sys.version_info[:2]
84
REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
86
REQUIRED_MODULES.extend(['_weakrefset'])
88
REQUIRED_MODULES.extend(['sets', '__future__'])
90
# Some extra modules are needed for Python 3, but different ones
91
# for different versions.
92
REQUIRED_MODULES.extend(['_abcoll', 'warnings', 'linecache', 'abc', 'io',
93
'_weakrefset', 'copyreg', 'tempfile', 'random',
94
'__future__', 'collections', 'keyword', 'tarfile',
95
'shutil', 'struct', 'copy'])
97
REQUIRED_FILES[-1] = 'config-%s' % majver
99
# The whole list of 3.3 modules is reproduced below - the current
100
# uncommented ones are required for 3.3 as of now, but more may be
101
# added as 3.3 development continues.
102
REQUIRED_MODULES.extend([
251
# these are needed to correctly display the exceptions that may happen
252
# during the bootstrap
253
REQUIRED_MODULES.extend(['traceback', 'linecache'])
255
class Logger(object):
258
Logging object for use in command-line script. Allows ranges of
259
levels, to avoid some redundancy of displayed information.
262
DEBUG = logging.DEBUG
264
NOTIFY = (logging.INFO+logging.WARN)/2
265
WARN = WARNING = logging.WARN
266
ERROR = logging.ERROR
267
FATAL = logging.FATAL
269
LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
271
def __init__(self, consumers):
272
self.consumers = consumers
274
self.in_progress = None
275
self.in_progress_hanging = False
277
def debug(self, msg, *args, **kw):
278
self.log(self.DEBUG, msg, *args, **kw)
279
def info(self, msg, *args, **kw):
280
self.log(self.INFO, msg, *args, **kw)
281
def notify(self, msg, *args, **kw):
282
self.log(self.NOTIFY, msg, *args, **kw)
283
def warn(self, msg, *args, **kw):
284
self.log(self.WARN, msg, *args, **kw)
285
def error(self, msg, *args, **kw):
286
self.log(self.WARN, msg, *args, **kw)
287
def fatal(self, msg, *args, **kw):
288
self.log(self.FATAL, msg, *args, **kw)
289
def log(self, level, msg, *args, **kw):
293
"You may give positional or keyword arguments, not both")
296
for consumer_level, consumer in self.consumers:
297
if self.level_matches(level, consumer_level):
298
if (self.in_progress_hanging
299
and consumer in (sys.stdout, sys.stderr)):
300
self.in_progress_hanging = False
301
sys.stdout.write('\n')
305
rendered = msg % args
308
rendered = ' '*self.indent + rendered
309
if hasattr(consumer, 'write'):
310
consumer.write(rendered+'\n')
314
def start_progress(self, msg):
315
assert not self.in_progress, (
316
"Tried to start_progress(%r) while in_progress %r"
317
% (msg, self.in_progress))
318
if self.level_matches(self.NOTIFY, self._stdout_level()):
319
sys.stdout.write(msg)
321
self.in_progress_hanging = True
323
self.in_progress_hanging = False
324
self.in_progress = msg
326
def end_progress(self, msg='done.'):
327
assert self.in_progress, (
328
"Tried to end_progress without start_progress")
329
if self.stdout_level_matches(self.NOTIFY):
330
if not self.in_progress_hanging:
331
# Some message has been printed out since start_progress
332
sys.stdout.write('...' + self.in_progress + msg + '\n')
335
sys.stdout.write(msg + '\n')
337
self.in_progress = None
338
self.in_progress_hanging = False
340
def show_progress(self):
341
"""If we are in a progress scope, and no log messages have been
342
shown, write out another '.'"""
343
if self.in_progress_hanging:
344
sys.stdout.write('.')
347
def stdout_level_matches(self, level):
348
"""Returns true if a message at this level will go to stdout"""
349
return self.level_matches(level, self._stdout_level())
351
def _stdout_level(self):
352
"""Returns the level that stdout runs at"""
353
for level, consumer in self.consumers:
354
if consumer is sys.stdout:
358
def level_matches(self, level, consumer_level):
361
>>> l.level_matches(3, 4)
363
>>> l.level_matches(3, 2)
365
>>> l.level_matches(slice(None, 3), 3)
367
>>> l.level_matches(slice(None, 3), 2)
369
>>> l.level_matches(slice(1, 3), 1)
371
>>> l.level_matches(slice(2, 3), 1)
374
if isinstance(level, slice):
375
start, stop = level.start, level.stop
376
if start is not None and start > consumer_level:
378
if stop is not None and stop <= consumer_level:
382
return level >= consumer_level
385
def level_for_integer(cls, level):
389
if level >= len(levels):
393
level_for_integer = classmethod(level_for_integer)
395
# create a silent logger just to prevent this from being undefined
396
# will be overridden with requested verbosity main() is called.
397
logger = Logger([(Logger.LEVELS[-1], sys.stdout)])
400
if not os.path.exists(path):
401
logger.info('Creating %s', path)
404
logger.info('Directory %s already exists', path)
406
def copyfileordir(src, dest):
407
if os.path.isdir(src):
408
shutil.copytree(src, dest, True)
410
shutil.copy2(src, dest)
412
def copyfile(src, dest, symlink=True):
413
if not os.path.exists(src):
414
# Some bad symlink in the src
415
logger.warn('Cannot find file %s (bad symlink)', src)
417
if os.path.exists(dest):
418
logger.debug('File %s already exists', dest)
420
if not os.path.exists(os.path.dirname(dest)):
421
logger.info('Creating parent directories for %s' % os.path.dirname(dest))
422
os.makedirs(os.path.dirname(dest))
423
if not os.path.islink(src):
424
srcpath = os.path.abspath(src)
426
srcpath = os.readlink(src)
427
if symlink and hasattr(os, 'symlink') and not is_win:
428
logger.info('Symlinking %s', dest)
430
os.symlink(srcpath, dest)
431
except (OSError, NotImplementedError):
432
logger.info('Symlinking failed, copying to %s', dest)
433
copyfileordir(src, dest)
435
logger.info('Copying to %s', dest)
436
copyfileordir(src, dest)
438
def writefile(dest, content, overwrite=True):
439
if not os.path.exists(dest):
440
logger.info('Writing %s', dest)
442
f.write(content.encode('utf-8'))
449
if c != content.encode("utf-8"):
451
logger.notify('File %s exists with different content; not overwriting', dest)
453
logger.notify('Overwriting %s with new content', dest)
455
f.write(content.encode('utf-8'))
458
logger.info('Content %s already in place', dest)
461
if os.path.exists(dir):
462
logger.notify('Deleting tree %s', dir)
465
logger.info('Do not need to delete %s; already gone', dir)
468
if hasattr(os, 'chmod'):
469
oldmode = os.stat(fn).st_mode & 0xFFF # 0o7777
470
newmode = (oldmode | 0x16D) & 0xFFF # 0o555, 0o7777
471
os.chmod(fn, newmode)
472
logger.info('Changed mode of %s to %s', fn, oct(newmode))
474
def _find_file(filename, dirs):
475
for dir in reversed(dirs):
476
if os.path.exists(join(dir, filename)):
477
return join(dir, filename)
480
def _install_req(py_executable, unzip=False, distribute=False,
481
search_dirs=None, never_download=False):
483
if search_dirs is None:
484
search_dirs = file_search_dirs()
487
setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3]
488
project_name = 'setuptools'
489
bootstrap_script = EZ_SETUP_PY
493
source = 'distribute-0.6.27.tar.gz'
494
project_name = 'distribute'
495
bootstrap_script = DISTRIBUTE_SETUP_PY
497
if setup_fn is not None:
498
setup_fn = _find_file(setup_fn, search_dirs)
500
if source is not None:
501
source = _find_file(source, search_dirs)
503
if is_jython and os._name == 'nt':
504
# Jython's .bat sys.executable can't handle a command line
505
# argument with newlines
506
fd, ez_setup = tempfile.mkstemp('.py')
507
os.write(fd, bootstrap_script)
509
cmd = [py_executable, ez_setup]
511
cmd = [py_executable, '-c', bootstrap_script]
513
cmd.append('--always-unzip')
516
if logger.stdout_level_matches(logger.DEBUG):
519
old_chdir = os.getcwd()
520
if setup_fn is not None and os.path.exists(setup_fn):
521
logger.info('Using existing %s egg: %s' % (project_name, setup_fn))
523
if os.environ.get('PYTHONPATH'):
524
env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH']
526
env['PYTHONPATH'] = setup_fn
528
# the source is found, let's chdir
529
if source is not None and os.path.exists(source):
530
logger.info('Using existing %s egg: %s' % (project_name, source))
531
os.chdir(os.path.dirname(source))
532
# in this case, we want to be sure that PYTHONPATH is unset (not
533
# just empty, really unset), else CPython tries to import the
534
# site.py that it's in virtualenv_support
535
remove_from_env.append('PYTHONPATH')
538
logger.fatal("Can't find any local distributions of %s to install "
539
"and --never-download is set. Either re-run virtualenv "
540
"without the --never-download option, or place a %s "
541
"distribution (%s) in one of these "
542
"locations: %r" % (project_name, project_name,
547
logger.info('No %s egg found; downloading' % project_name)
548
cmd.extend(['--always-copy', '-U', project_name])
549
logger.start_progress('Installing %s...' % project_name)
552
if project_name == 'distribute':
553
env['DONT_PATCH_SETUPTOOLS'] = 'true'
555
def _filter_ez_setup(line):
556
return filter_ez_setup(line, project_name)
558
if not os.access(os.getcwd(), os.W_OK):
559
cwd = tempfile.mkdtemp()
560
if source is not None and os.path.exists(source):
561
# the current working dir is hostile, let's copy the
562
# tarball to a temp dir
563
target = os.path.join(cwd, os.path.split(source)[-1])
564
shutil.copy(source, target)
566
call_subprocess(cmd, show_stdout=False,
567
filter_stdout=_filter_ez_setup,
569
remove_from_env=remove_from_env,
573
logger.end_progress()
576
if os.getcwd() != old_chdir:
578
if is_jython and os._name == 'nt':
581
def file_search_dirs():
582
here = os.path.dirname(os.path.abspath(__file__))
584
join(here, 'virtualenv_support')]
585
if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
586
# Probably some boot script; just in case virtualenv is installed...
592
dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
593
return [d for d in dirs if os.path.isdir(d)]
595
def install_setuptools(py_executable, unzip=False,
596
search_dirs=None, never_download=False):
597
_install_req(py_executable, unzip,
598
search_dirs=search_dirs, never_download=never_download)
600
def install_distribute(py_executable, unzip=False,
601
search_dirs=None, never_download=False):
602
_install_req(py_executable, unzip, distribute=True,
603
search_dirs=search_dirs, never_download=never_download)
605
_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I)
606
def install_pip(py_executable, search_dirs=None, never_download=False):
607
if search_dirs is None:
608
search_dirs = file_search_dirs()
611
for dir in search_dirs:
612
filenames.extend([join(dir, fn) for fn in os.listdir(dir)
613
if _pip_re.search(fn)])
614
filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)]
616
filenames = [filename for basename, i, filename in filenames]
620
filename = filenames[-1]
621
easy_install_script = 'easy_install'
622
if sys.platform == 'win32':
623
easy_install_script = 'easy_install-script.py'
624
# There's two subtle issues here when invoking easy_install.
625
# 1. On unix-like systems the easy_install script can *only* be executed
626
# directly if its full filesystem path is no longer than 78 characters.
627
# 2. A work around to [1] is to use the `python path/to/easy_install foo`
628
# pattern, but that breaks if the path contains non-ASCII characters, as
629
# you can't put the file encoding declaration before the shebang line.
630
# The solution is to use Python's -x flag to skip the first line of the
631
# script (and any ASCII decoding errors that may have occurred in that line)
632
cmd = [py_executable, '-x', join(os.path.dirname(py_executable), easy_install_script), filename]
633
# jython and pypy don't yet support -x
634
if is_jython or is_pypy:
636
if filename == 'pip':
638
logger.fatal("Can't find any local distributions of pip to install "
639
"and --never-download is set. Either re-run virtualenv "
640
"without the --never-download option, or place a pip "
641
"source distribution (zip/tar.gz/tar.bz2) in one of these "
642
"locations: %r" % search_dirs)
644
logger.info('Installing pip from network...')
646
logger.info('Installing existing %s distribution: %s' % (
647
os.path.basename(filename), filename))
648
logger.start_progress('Installing pip...')
650
def _filter_setup(line):
651
return filter_ez_setup(line, 'pip')
653
call_subprocess(cmd, show_stdout=False,
654
filter_stdout=_filter_setup)
657
logger.end_progress()
659
def filter_ez_setup(line, project_name='setuptools'):
662
if project_name == 'distribute':
663
for prefix in ('Extracting', 'Now working', 'Installing', 'Before',
664
'Scanning', 'Setuptools', 'Egg', 'Already',
665
'running', 'writing', 'reading', 'installing',
666
'creating', 'copying', 'byte-compiling', 'removing',
668
if line.startswith(prefix):
671
for prefix in ['Reading ', 'Best match', 'Processing setuptools',
672
'Copying setuptools', 'Adding setuptools',
673
'Installing ', 'Installed ']:
674
if line.startswith(prefix):
679
class UpdatingDefaultsHelpFormatter(optparse.IndentedHelpFormatter):
681
Custom help formatter for use in ConfigOptionParser that updates
682
the defaults before expanding them, allowing them to show up correctly
685
def expand_default(self, option):
686
if self.parser is not None:
687
self.parser.update_defaults(self.parser.defaults)
688
return optparse.IndentedHelpFormatter.expand_default(self, option)
691
class ConfigOptionParser(optparse.OptionParser):
693
Custom option parser which updates its defaults by by checking the
694
configuration files and environmental variables
696
def __init__(self, *args, **kwargs):
697
self.config = ConfigParser.RawConfigParser()
698
self.files = self.get_config_files()
699
self.config.read(self.files)
700
optparse.OptionParser.__init__(self, *args, **kwargs)
702
def get_config_files(self):
703
config_file = os.environ.get('VIRTUALENV_CONFIG_FILE', False)
704
if config_file and os.path.exists(config_file):
706
return [default_config_file]
708
def update_defaults(self, defaults):
710
Updates the given defaults with values from the config files and
711
the environ. Does a little special handling for certain types of
714
# Then go and look for the other sources of configuration:
717
config.update(dict(self.get_config_section('virtualenv')))
718
# 2. environmental variables
719
config.update(dict(self.get_environ_vars()))
720
# Then set the options with those values
721
for key, val in config.items():
722
key = key.replace('_', '-')
723
if not key.startswith('--'):
724
key = '--%s' % key # only prefer long opts
725
option = self.get_option(key)
726
if option is not None:
727
# ignore empty values
730
# handle multiline configs
731
if option.action == 'append':
735
if option.action in ('store_true', 'store_false', 'count'):
738
val = option.convert_value(key, val)
739
except optparse.OptionValueError:
740
e = sys.exc_info()[1]
741
print("An error occured during configuration: %s" % e)
743
defaults[option.dest] = val
746
def get_config_section(self, name):
748
Get a section of a configuration
750
if self.config.has_section(name):
751
return self.config.items(name)
754
def get_environ_vars(self, prefix='VIRTUALENV_'):
756
Returns a generator with all environmental vars with prefix VIRTUALENV
758
for key, val in os.environ.items():
759
if key.startswith(prefix):
760
yield (key.replace(prefix, '').lower(), val)
762
def get_default_values(self):
764
Overridding to make updating the defaults after instantiation of
765
the option parser possible, update_defaults() does the dirty work.
767
if not self.process_default_values:
768
# Old, pre-Optik 1.5 behaviour.
769
return optparse.Values(self.defaults)
771
defaults = self.update_defaults(self.defaults.copy()) # ours
772
for option in self._get_all_options():
773
default = defaults.get(option.dest)
774
if isinstance(default, basestring):
775
opt_str = option.get_opt_string()
776
defaults[option.dest] = option.check_value(opt_str, default)
777
return optparse.Values(defaults)
781
parser = ConfigOptionParser(
782
version=virtualenv_version,
783
usage="%prog [OPTIONS] DEST_DIR",
784
formatter=UpdatingDefaultsHelpFormatter())
791
help="Increase verbosity")
798
help='Decrease verbosity')
803
metavar='PYTHON_EXE',
804
help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
805
'interpreter to create the new environment. The default is the interpreter that '
806
'virtualenv was installed with (%s)' % sys.executable)
812
help="Clear out the non-root install and start from scratch")
814
parser.set_defaults(system_site_packages=False)
816
'--no-site-packages',
817
dest='system_site_packages',
818
action='store_false',
819
help="Don't give access to the global site-packages dir to the "
820
"virtual environment (default)")
823
'--system-site-packages',
824
dest='system_site_packages',
826
help="Give access to the global site-packages dir to the "
827
"virtual environment")
830
'--unzip-setuptools',
831
dest='unzip_setuptools',
833
help="Unzip Setuptools or Distribute when installing it")
839
help='Make an EXISTING virtualenv environment relocatable. '
840
'This fixes up scripts and makes all .pth files relative')
843
'--distribute', '--use-distribute', # the second option is for legacy reasons here. Hi Kenneth!
844
dest='use_distribute',
846
help='Use Distribute instead of Setuptools. Set environ variable '
847
'VIRTUALENV_DISTRIBUTE to make it the default ')
849
default_search_dirs = file_search_dirs()
851
'--extra-search-dir',
854
default=default_search_dirs,
855
help="Directory to look for setuptools/distribute/pip distributions in. "
856
"You can add any number of additional --extra-search-dir paths.")
860
dest="never_download",
862
help="Never download anything from the network. Instead, virtualenv will fail "
863
"if local distributions of setuptools/distribute/pip are not present.")
868
help='Provides an alternative prompt prefix for this environment')
870
if 'extend_parser' in globals():
871
extend_parser(parser)
873
options, args = parser.parse_args()
877
if 'adjust_options' in globals():
878
adjust_options(options, args)
880
verbosity = options.verbose - options.quiet
881
logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)])
883
if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
884
env = os.environ.copy()
885
interpreter = resolve_interpreter(options.python)
886
if interpreter == sys.executable:
887
logger.warn('Already using interpreter %s' % interpreter)
889
logger.notify('Running virtualenv with interpreter %s' % interpreter)
890
env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
892
if file.endswith('.pyc'):
894
popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
895
raise SystemExit(popen.wait())
897
# Force --distribute on Python 3, since setuptools is not available.
899
options.use_distribute = True
901
if os.environ.get('PYTHONDONTWRITEBYTECODE') and not options.use_distribute:
903
"The PYTHONDONTWRITEBYTECODE environment variable is "
904
"not compatible with setuptools. Either use --distribute "
905
"or unset PYTHONDONTWRITEBYTECODE.")
908
print('You must provide a DEST_DIR')
912
print('There must be only one argument: DEST_DIR (you gave %s)' % (
919
if os.environ.get('WORKING_ENV'):
920
logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
921
logger.fatal('Please deactivate your workingenv, then re-run this script')
924
if 'PYTHONHOME' in os.environ:
925
logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it')
926
del os.environ['PYTHONHOME']
928
if options.relocatable:
929
make_environment_relocatable(home_dir)
932
create_environment(home_dir,
933
site_packages=options.system_site_packages,
935
unzip_setuptools=options.unzip_setuptools,
936
use_distribute=options.use_distribute,
937
prompt=options.prompt,
938
search_dirs=options.search_dirs,
939
never_download=options.never_download)
940
if 'after_install' in globals():
941
after_install(options, home_dir)
943
def call_subprocess(cmd, show_stdout=True,
944
filter_stdout=None, cwd=None,
945
raise_on_returncode=True, extra_env=None,
946
remove_from_env=None):
950
part = part[:20]+"..."+part[-20:]
951
if ' ' in part or '\n' in part or '"' in part or "'" in part:
952
part = '"%s"' % part.replace('"', '\\"')
953
if hasattr(part, 'decode'):
955
part = part.decode(sys.getdefaultencoding())
956
except UnicodeDecodeError:
957
part = part.decode(sys.getfilesystemencoding())
958
cmd_parts.append(part)
959
cmd_desc = ' '.join(cmd_parts)
963
stdout = subprocess.PIPE
964
logger.debug("Running command %s" % cmd_desc)
965
if extra_env or remove_from_env:
966
env = os.environ.copy()
968
env.update(extra_env)
970
for varname in remove_from_env:
971
env.pop(varname, None)
975
proc = subprocess.Popen(
976
cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
979
e = sys.exc_info()[1]
981
"Error %s while executing command %s" % (e, cmd_desc))
984
if stdout is not None:
986
encoding = sys.getdefaultencoding()
987
fs_encoding = sys.getfilesystemencoding()
989
line = stdout.readline()
991
line = line.decode(encoding)
992
except UnicodeDecodeError:
993
line = line.decode(fs_encoding)
997
all_output.append(line)
999
level = filter_stdout(line)
1000
if isinstance(level, tuple):
1002
logger.log(level, line)
1003
if not logger.stdout_level_matches(level):
1004
logger.show_progress()
1011
if raise_on_returncode:
1013
logger.notify('Complete output from command %s:' % cmd_desc)
1014
logger.notify('\n'.join(all_output) + '\n----------------------------------------')
1016
"Command %s failed with error code %s"
1017
% (cmd_desc, proc.returncode))
1020
"Command %s had error code %s"
1021
% (cmd_desc, proc.returncode))
1024
def create_environment(home_dir, site_packages=False, clear=False,
1025
unzip_setuptools=False, use_distribute=False,
1026
prompt=None, search_dirs=None, never_download=False):
1028
Creates a new environment in ``home_dir``.
1030
If ``site_packages`` is true, then the global ``site-packages/``
1031
directory will be on the path.
1033
If ``clear`` is true (default False) then the environment will
1036
home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
1038
py_executable = os.path.abspath(install_python(
1039
home_dir, lib_dir, inc_dir, bin_dir,
1040
site_packages=site_packages, clear=clear))
1042
install_distutils(home_dir)
1045
install_distribute(py_executable, unzip=unzip_setuptools,
1046
search_dirs=search_dirs, never_download=never_download)
1048
install_setuptools(py_executable, unzip=unzip_setuptools,
1049
search_dirs=search_dirs, never_download=never_download)
1051
install_pip(py_executable, search_dirs=search_dirs, never_download=never_download)
1053
install_activate(home_dir, bin_dir, prompt)
1055
def path_locations(home_dir):
1056
"""Return the path locations for the environment (where libraries are,
1057
where scripts go, etc)"""
1058
# XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
1059
# prefix arg is broken: http://bugs.python.org/issue3386
1060
if sys.platform == 'win32':
1061
# Windows has lots of problems with executables with spaces in
1062
# the name; this function will remove them (using the ~1
1069
print('Error: the path "%s" has a space in it' % home_dir)
1070
print('To handle these kinds of paths, the win32api module must be installed:')
1071
print(' http://sourceforge.net/projects/pywin32/')
1073
home_dir = win32api.GetShortPathName(home_dir)
1074
lib_dir = join(home_dir, 'Lib')
1075
inc_dir = join(home_dir, 'Include')
1076
bin_dir = join(home_dir, 'Scripts')
1078
lib_dir = join(home_dir, 'Lib')
1079
inc_dir = join(home_dir, 'Include')
1080
bin_dir = join(home_dir, 'bin')
1083
inc_dir = join(home_dir, 'include')
1084
bin_dir = join(home_dir, 'bin')
1085
elif sys.platform != 'win32':
1086
lib_dir = join(home_dir, 'lib', py_version)
1087
inc_dir = join(home_dir, 'include', py_version + abiflags)
1088
bin_dir = join(home_dir, 'bin')
1089
return home_dir, lib_dir, inc_dir, bin_dir
1092
def change_prefix(filename, dst_prefix):
1093
prefixes = [sys.prefix]
1095
if sys.platform == "darwin":
1097
os.path.join("/Library/Python", sys.version[:3], "site-packages"),
1098
os.path.join(sys.prefix, "Extras", "lib", "python"),
1099
os.path.join("~", "Library", "Python", sys.version[:3], "site-packages")))
1101
if hasattr(sys, 'real_prefix'):
1102
prefixes.append(sys.real_prefix)
1103
prefixes = list(map(os.path.abspath, prefixes))
1104
filename = os.path.abspath(filename)
1105
for src_prefix in prefixes:
1106
if filename.startswith(src_prefix):
1107
_, relpath = filename.split(src_prefix, 1)
1108
if src_prefix != os.sep: # sys.prefix == "/"
1109
assert relpath[0] == os.sep
1110
relpath = relpath[1:]
1111
return join(dst_prefix, relpath)
1112
assert False, "Filename %s does not start with any of these prefixes: %s" % \
1113
(filename, prefixes)
1115
def copy_required_modules(dst_prefix):
1117
# If we are running under -p, we need to remove the current
1118
# directory from sys.path temporarily here, so that we
1119
# definitely get the modules from the site directory of
1120
# the interpreter we are running under, not the one
1121
# virtualenv.py is installed under (which might lead to py2/py3
1122
# incompatibility issues)
1123
_prev_sys_path = sys.path
1124
if os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
1125
sys.path = sys.path[1:]
1127
for modname in REQUIRED_MODULES:
1128
if modname in sys.builtin_module_names:
1129
logger.info("Ignoring built-in bootstrap module: %s" % modname)
1132
f, filename, _ = imp.find_module(modname)
1134
logger.info("Cannot import bootstrap module: %s" % modname)
1138
dst_filename = change_prefix(filename, dst_prefix)
1139
copyfile(filename, dst_filename)
1140
if filename.endswith('.pyc'):
1141
pyfile = filename[:-1]
1142
if os.path.exists(pyfile):
1143
copyfile(pyfile, dst_filename[:-1])
1145
sys.path = _prev_sys_path
1147
def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
1148
"""Install just the base environment, no distutils patches etc"""
1149
if sys.executable.startswith(bin_dir):
1150
print('Please use the *system* python to run this script')
1155
## FIXME: why not delete it?
1156
## Maybe it should delete everything with #!/path/to/venv/python in it
1157
logger.notify('Not deleting %s', bin_dir)
1159
if hasattr(sys, 'real_prefix'):
1160
logger.notify('Using real prefix %r' % sys.real_prefix)
1161
prefix = sys.real_prefix
1166
stdlib_dirs = [os.path.dirname(os.__file__)]
1167
if sys.platform == 'win32':
1168
stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
1169
elif sys.platform == 'darwin':
1170
stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
1171
if hasattr(os, 'symlink'):
1172
logger.info('Symlinking Python bootstrap modules')
1174
logger.info('Copying Python bootstrap modules')
1177
# copy required files...
1178
for stdlib_dir in stdlib_dirs:
1179
if not os.path.isdir(stdlib_dir):
1181
for fn in os.listdir(stdlib_dir):
1182
bn = os.path.splitext(fn)[0]
1183
if fn != 'site-packages' and bn in REQUIRED_FILES:
1184
copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
1186
copy_required_modules(home_dir)
1189
mkdir(join(lib_dir, 'site-packages'))
1191
site_filename = site.__file__
1192
if site_filename.endswith('.pyc'):
1193
site_filename = site_filename[:-1]
1194
elif site_filename.endswith('$py.class'):
1195
site_filename = site_filename.replace('$py.class', '.py')
1196
site_filename_dst = change_prefix(site_filename, home_dir)
1197
site_dir = os.path.dirname(site_filename_dst)
1198
writefile(site_filename_dst, SITE_PY)
1199
writefile(join(site_dir, 'orig-prefix.txt'), prefix)
1200
site_packages_filename = join(site_dir, 'no-global-site-packages.txt')
1201
if not site_packages:
1202
writefile(site_packages_filename, '')
1204
if os.path.exists(site_packages_filename):
1205
logger.info('Deleting %s' % site_packages_filename)
1206
os.unlink(site_packages_filename)
1208
if is_pypy or is_win:
1209
stdinc_dir = join(prefix, 'include')
1211
stdinc_dir = join(prefix, 'include', py_version + abiflags)
1212
if os.path.exists(stdinc_dir):
1213
copyfile(stdinc_dir, inc_dir)
1215
logger.debug('No include dir %s' % stdinc_dir)
1217
# pypy never uses exec_prefix, just ignore it
1218
if sys.exec_prefix != prefix and not is_pypy:
1219
if sys.platform == 'win32':
1220
exec_dir = join(sys.exec_prefix, 'lib')
1222
exec_dir = join(sys.exec_prefix, 'Lib')
1224
exec_dir = join(sys.exec_prefix, 'lib', py_version)
1225
for fn in os.listdir(exec_dir):
1226
copyfile(join(exec_dir, fn), join(lib_dir, fn))
1229
# Jython has either jython-dev.jar and javalib/ dir, or just
1231
for name in 'jython-dev.jar', 'javalib', 'jython.jar':
1232
src = join(prefix, name)
1233
if os.path.exists(src):
1234
copyfile(src, join(home_dir, name))
1235
# XXX: registry should always exist after Jython 2.5rc1
1236
src = join(prefix, 'registry')
1237
if os.path.exists(src):
1238
copyfile(src, join(home_dir, 'registry'), symlink=False)
1239
copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
1243
py_executable = join(bin_dir, os.path.basename(sys.executable))
1244
if 'Python.framework' in prefix:
1245
if re.search(r'/Python(?:-32|-64)*$', py_executable):
1246
# The name of the python executable is not quite what
1247
# we want, rename it.
1248
py_executable = os.path.join(
1249
os.path.dirname(py_executable), 'python')
1251
logger.notify('New %s executable in %s', expected_exe, py_executable)
1252
pcbuild_dir = os.path.dirname(sys.executable)
1253
pyd_pth = os.path.join(lib_dir, 'site-packages', 'virtualenv_builddir_pyd.pth')
1254
if is_win and os.path.exists(os.path.join(pcbuild_dir, 'build.bat')):
1255
logger.notify('Detected python running from build directory %s', pcbuild_dir)
1256
logger.notify('Writing .pth file linking to build directory for *.pyd files')
1257
writefile(pyd_pth, pcbuild_dir)
1260
if os.path.exists(pyd_pth):
1261
logger.info('Deleting %s (not Windows env or not build directory python)' % pyd_pth)
1264
if sys.executable != py_executable:
1265
## FIXME: could I just hard link?
1266
executable = sys.executable
1267
if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'):
1268
# Cygwin misreports sys.executable sometimes
1269
executable += '.exe'
1270
py_executable += '.exe'
1271
logger.info('Executable actually exists in %s' % executable)
1272
shutil.copyfile(executable, py_executable)
1273
make_exe(py_executable)
1274
if sys.platform == 'win32' or sys.platform == 'cygwin':
1275
pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
1276
if os.path.exists(pythonw):
1277
logger.info('Also created pythonw.exe')
1278
shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
1279
python_d = os.path.join(os.path.dirname(sys.executable), 'python_d.exe')
1280
python_d_dest = os.path.join(os.path.dirname(py_executable), 'python_d.exe')
1281
if os.path.exists(python_d):
1282
logger.info('Also created python_d.exe')
1283
shutil.copyfile(python_d, python_d_dest)
1284
elif os.path.exists(python_d_dest):
1285
logger.info('Removed python_d.exe as it is no longer at the source')
1286
os.unlink(python_d_dest)
1287
# we need to copy the DLL to enforce that windows will load the correct one.
1288
# may not exist if we are cygwin.
1289
py_executable_dll = 'python%s%s.dll' % (
1290
sys.version_info[0], sys.version_info[1])
1291
py_executable_dll_d = 'python%s%s_d.dll' % (
1292
sys.version_info[0], sys.version_info[1])
1293
pythondll = os.path.join(os.path.dirname(sys.executable), py_executable_dll)
1294
pythondll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d)
1295
pythondll_d_dest = os.path.join(os.path.dirname(py_executable), py_executable_dll_d)
1296
if os.path.exists(pythondll):
1297
logger.info('Also created %s' % py_executable_dll)
1298
shutil.copyfile(pythondll, os.path.join(os.path.dirname(py_executable), py_executable_dll))
1299
if os.path.exists(pythondll_d):
1300
logger.info('Also created %s' % py_executable_dll_d)
1301
shutil.copyfile(pythondll_d, pythondll_d_dest)
1302
elif os.path.exists(pythondll_d_dest):
1303
logger.info('Removed %s as the source does not exist' % pythondll_d_dest)
1304
os.unlink(pythondll_d_dest)
1306
# make a symlink python --> pypy-c
1307
python_executable = os.path.join(os.path.dirname(py_executable), 'python')
1308
if sys.platform in ('win32', 'cygwin'):
1309
python_executable += '.exe'
1310
logger.info('Also created executable %s' % python_executable)
1311
copyfile(py_executable, python_executable)
1313
if sys.platform == 'win32':
1314
for name in 'libexpat.dll', 'libpypy.dll', 'libpypy-c.dll', 'libeay32.dll', 'ssleay32.dll', 'sqlite.dll':
1315
src = join(prefix, name)
1316
if os.path.exists(src):
1317
copyfile(src, join(bin_dir, name))
1319
if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
1320
secondary_exe = os.path.join(os.path.dirname(py_executable),
1322
py_executable_ext = os.path.splitext(py_executable)[1]
1323
if py_executable_ext == '.exe':
1324
# python2.4 gives an extension of '.4' :P
1325
secondary_exe += py_executable_ext
1326
if os.path.exists(secondary_exe):
1327
logger.warn('Not overwriting existing %s script %s (you must use %s)'
1328
% (expected_exe, secondary_exe, py_executable))
1330
logger.notify('Also creating executable in %s' % secondary_exe)
1331
shutil.copyfile(sys.executable, secondary_exe)
1332
make_exe(secondary_exe)
1334
if '.framework' in prefix:
1335
if 'Python.framework' in prefix:
1336
logger.debug('MacOSX Python framework detected')
1337
# Make sure we use the the embedded interpreter inside
1338
# the framework, even if sys.executable points to
1339
# the stub executable in ${sys.prefix}/bin
1340
# See http://groups.google.com/group/python-virtualenv/
1341
# browse_thread/thread/17cab2f85da75951
1342
original_python = os.path.join(
1343
prefix, 'Resources/Python.app/Contents/MacOS/Python')
1345
logger.debug('EPD framework detected')
1346
original_python = os.path.join(prefix, 'bin/python')
1347
shutil.copy(original_python, py_executable)
1349
# Copy the framework's dylib into the virtual
1351
virtual_lib = os.path.join(home_dir, '.Python')
1353
if os.path.exists(virtual_lib):
1354
os.unlink(virtual_lib)
1356
os.path.join(prefix, 'Python'),
1359
# And then change the install_name of the copied python executable
1361
mach_o_change(py_executable,
1362
os.path.join(prefix, 'Python'),
1363
'@executable_path/../.Python')
1365
e = sys.exc_info()[1]
1366
logger.warn("Could not call mach_o_change: %s. "
1367
"Trying to call install_name_tool instead." % e)
1370
["install_name_tool", "-change",
1371
os.path.join(prefix, 'Python'),
1372
'@executable_path/../.Python',
1375
logger.fatal("Could not call install_name_tool -- you must "
1376
"have Apple's development tools installed")
1379
# Some tools depend on pythonX.Y being present
1380
py_executable_version = '%s.%s' % (
1381
sys.version_info[0], sys.version_info[1])
1382
if not py_executable.endswith(py_executable_version):
1383
# symlinking pythonX.Y > python
1384
pth = py_executable + '%s.%s' % (
1385
sys.version_info[0], sys.version_info[1])
1386
if os.path.exists(pth):
1388
os.symlink('python', pth)
1390
# reverse symlinking python -> pythonX.Y (with --python)
1391
pth = join(bin_dir, 'python')
1392
if os.path.exists(pth):
1394
os.symlink(os.path.basename(py_executable), pth)
1396
if sys.platform == 'win32' and ' ' in py_executable:
1397
# There's a bug with subprocess on Windows when using a first
1398
# argument that has a space in it. Instead we have to quote
1400
py_executable = '"%s"' % py_executable
1401
# NOTE: keep this check as one line, cmd.exe doesn't cope with line breaks
1402
cmd = [py_executable, '-c', 'import sys;out=sys.stdout;'
1403
'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))']
1404
logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
1406
proc = subprocess.Popen(cmd,
1407
stdout=subprocess.PIPE)
1408
proc_stdout, proc_stderr = proc.communicate()
1410
e = sys.exc_info()[1]
1411
if e.errno == errno.EACCES:
1412
logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e))
1417
proc_stdout = proc_stdout.strip().decode("utf-8")
1418
proc_stdout = os.path.normcase(os.path.abspath(proc_stdout))
1419
norm_home_dir = os.path.normcase(os.path.abspath(home_dir))
1420
if hasattr(norm_home_dir, 'decode'):
1421
norm_home_dir = norm_home_dir.decode(sys.getfilesystemencoding())
1422
if proc_stdout != norm_home_dir:
1424
'ERROR: The executable %s is not functioning' % py_executable)
1426
'ERROR: It thinks sys.prefix is %r (should be %r)'
1427
% (proc_stdout, norm_home_dir))
1429
'ERROR: virtualenv is not compatible with this system or executable')
1430
if sys.platform == 'win32':
1432
'Note: some Windows users have reported this error when they '
1433
'installed Python for "Only this user" or have multiple '
1434
'versions of Python installed. Copying the appropriate '
1435
'PythonXX.dll to the virtualenv Scripts/ directory may fix '
1439
logger.info('Got sys.prefix result: %r' % proc_stdout)
1441
pydistutils = os.path.expanduser('~/.pydistutils.cfg')
1442
if os.path.exists(pydistutils):
1443
logger.notify('Please make sure you remove any previous custom paths from '
1444
'your %s file.' % pydistutils)
1445
## FIXME: really this should be calculated earlier
1447
fix_local_scheme(home_dir)
1449
return py_executable
1452
def install_activate(home_dir, bin_dir, prompt=None):
1453
home_dir = os.path.abspath(home_dir)
1454
if sys.platform == 'win32' or is_jython and os._name == 'nt':
1456
'activate.bat': ACTIVATE_BAT,
1457
'deactivate.bat': DEACTIVATE_BAT,
1458
'activate.ps1': ACTIVATE_PS,
1461
# MSYS needs paths of the form /c/path/to/file
1462
drive, tail = os.path.splitdrive(home_dir.replace(os.sep, '/'))
1463
home_dir_msys = (drive and "/%s%s" or "%s%s") % (drive[:1], tail)
1465
# Run-time conditional enables (basic) Cygwin compatibility
1466
home_dir_sh = ("""$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '%s'; else echo '%s'; fi;)""" %
1467
(home_dir, home_dir_msys))
1468
files['activate'] = ACTIVATE_SH.replace('__VIRTUAL_ENV__', home_dir_sh)
1471
files = {'activate': ACTIVATE_SH}
1473
# suppling activate.fish in addition to, not instead of, the
1474
# bash script support.
1475
files['activate.fish'] = ACTIVATE_FISH
1477
# same for csh/tcsh support...
1478
files['activate.csh'] = ACTIVATE_CSH
1480
files['activate_this.py'] = ACTIVATE_THIS
1481
if hasattr(home_dir, 'decode'):
1482
home_dir = home_dir.decode(sys.getfilesystemencoding())
1483
vname = os.path.basename(home_dir)
1484
for name, content in files.items():
1485
content = content.replace('__VIRTUAL_PROMPT__', prompt or '')
1486
content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)
1487
content = content.replace('__VIRTUAL_ENV__', home_dir)
1488
content = content.replace('__VIRTUAL_NAME__', vname)
1489
content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
1490
writefile(os.path.join(bin_dir, name), content)
1492
def install_distutils(home_dir):
1493
distutils_path = change_prefix(distutils.__path__[0], home_dir)
1494
mkdir(distutils_path)
1495
## FIXME: maybe this prefix setting should only be put in place if
1496
## there's a local distutils.cfg with a prefix setting?
1497
home_dir = os.path.abspath(home_dir)
1498
## FIXME: this is breaking things, removing for now:
1499
#distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
1500
writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
1501
writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
1503
def fix_local_scheme(home_dir):
1505
Platforms that use the "posix_local" install scheme (like Ubuntu with
1506
Python 2.7) need to be given an additional "local" location, sigh.
1513
if sysconfig._get_default_scheme() == 'posix_local':
1514
local_path = os.path.join(home_dir, 'local')
1515
if not os.path.exists(local_path):
1516
os.mkdir(local_path)
1517
for subdir_name in os.listdir(home_dir):
1518
if subdir_name == 'local':
1520
os.symlink(os.path.abspath(os.path.join(home_dir, subdir_name)), \
1521
os.path.join(local_path, subdir_name))
1523
def fix_lib64(lib_dir):
1525
Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
1526
instead of lib/pythonX.Y. If this is such a platform we'll just create a
1527
symlink so lib64 points to lib
1529
if [p for p in distutils.sysconfig.get_config_vars().values()
1530
if isinstance(p, basestring) and 'lib64' in p]:
1531
logger.debug('This system uses lib64; symlinking lib64 to lib')
1532
assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
1533
"Unexpected python lib dir: %r" % lib_dir)
1534
lib_parent = os.path.dirname(lib_dir)
1535
assert os.path.basename(lib_parent) == 'lib', (
1536
"Unexpected parent dir: %r" % lib_parent)
1537
copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64'))
1539
def resolve_interpreter(exe):
1541
If the executable given isn't an absolute path, search $PATH for the interpreter
1543
if os.path.abspath(exe) != exe:
1544
paths = os.environ.get('PATH', '').split(os.pathsep)
1546
if os.path.exists(os.path.join(path, exe)):
1547
exe = os.path.join(path, exe)
1549
if not os.path.exists(exe):
1550
logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
1552
if not is_executable(exe):
1553
logger.fatal('The executable %s (from --python=%s) is not executable' % (exe, exe))
1557
def is_executable(exe):
1558
"""Checks a file is executable"""
1559
return os.access(exe, os.X_OK)
1561
############################################################
1562
## Relocating the environment:
1564
def make_environment_relocatable(home_dir):
1566
Makes the already-existing environment use relative paths, and takes out
1567
the #!-based environment selection in scripts.
1569
home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
1570
activate_this = os.path.join(bin_dir, 'activate_this.py')
1571
if not os.path.exists(activate_this):
1573
'The environment doesn\'t have a file %s -- please re-run virtualenv '
1574
'on this environment to update it' % activate_this)
1575
fixup_scripts(home_dir)
1576
fixup_pth_and_egg_link(home_dir)
1577
## FIXME: need to fix up distutils.cfg
1579
OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
1580
'activate', 'activate.bat', 'activate_this.py']
1582
def fixup_scripts(home_dir):
1583
# This is what we expect at the top of scripts:
1584
shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
1585
# This is what we'll put:
1586
new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
1587
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"
1588
if sys.platform == 'win32':
1589
bin_suffix = 'Scripts'
1592
bin_dir = os.path.join(home_dir, bin_suffix)
1593
home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
1594
for filename in os.listdir(bin_dir):
1595
filename = os.path.join(bin_dir, filename)
1596
if not os.path.isfile(filename):
1597
# ignore subdirs, e.g. .svn ones.
1599
f = open(filename, 'rb')
1602
lines = f.read().decode('utf-8').splitlines()
1603
except UnicodeDecodeError:
1604
# This is probably a binary program instead
1605
# of a script, so just ignore it.
1610
logger.warn('Script %s is an empty file' % filename)
1612
if not lines[0].strip().startswith(shebang):
1613
if os.path.basename(filename) in OK_ABS_SCRIPTS:
1614
logger.debug('Cannot make script %s relative' % filename)
1615
elif lines[0].strip() == new_shebang:
1616
logger.info('Script %s has already been made relative' % filename)
1618
logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
1619
% (filename, shebang))
1621
logger.notify('Making script %s relative' % filename)
1622
lines = [new_shebang+'\n', activate+'\n'] + lines[1:]
1623
f = open(filename, 'wb')
1624
f.write('\n'.join(lines).encode('utf-8'))
1627
def fixup_pth_and_egg_link(home_dir, sys_path=None):
1628
"""Makes .pth and .egg-link files use relative paths"""
1629
home_dir = os.path.normcase(os.path.abspath(home_dir))
1630
if sys_path is None:
1632
for path in sys_path:
1635
if not os.path.isdir(path):
1637
path = os.path.normcase(os.path.abspath(path))
1638
if not path.startswith(home_dir):
1639
logger.debug('Skipping system (non-environment) directory %s' % path)
1641
for filename in os.listdir(path):
1642
filename = os.path.join(path, filename)
1643
if filename.endswith('.pth'):
1644
if not os.access(filename, os.W_OK):
1645
logger.warn('Cannot write .pth file %s, skipping' % filename)
1647
fixup_pth_file(filename)
1648
if filename.endswith('.egg-link'):
1649
if not os.access(filename, os.W_OK):
1650
logger.warn('Cannot write .egg-link file %s, skipping' % filename)
1652
fixup_egg_link(filename)
1654
def fixup_pth_file(filename):
1658
prev_lines = f.readlines()
1660
for line in prev_lines:
1662
if (not line or line.startswith('#') or line.startswith('import ')
1663
or os.path.abspath(line) != line):
1666
new_value = make_relative_path(filename, line)
1667
if line != new_value:
1668
logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
1669
lines.append(new_value)
1670
if lines == prev_lines:
1671
logger.info('No changes to .pth file %s' % filename)
1673
logger.notify('Making paths in .pth file %s relative' % filename)
1674
f = open(filename, 'w')
1675
f.write('\n'.join(lines) + '\n')
1678
def fixup_egg_link(filename):
1680
link = f.readline().strip()
1682
if os.path.abspath(link) != link:
1683
logger.debug('Link in %s already relative' % filename)
1685
new_link = make_relative_path(filename, link)
1686
logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
1687
f = open(filename, 'w')
1691
def make_relative_path(source, dest, dest_is_directory=True):
1693
Make a filename relative, where the filename is dest, and it is
1694
being referred to from the filename source.
1696
>>> make_relative_path('/usr/share/something/a-file.pth',
1697
... '/usr/share/another-place/src/Directory')
1698
'../another-place/src/Directory'
1699
>>> make_relative_path('/usr/share/something/a-file.pth',
1700
... '/home/user/src/Directory')
1701
'../../../home/user/src/Directory'
1702
>>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
1705
source = os.path.dirname(source)
1706
if not dest_is_directory:
1707
dest_filename = os.path.basename(dest)
1708
dest = os.path.dirname(dest)
1709
dest = os.path.normpath(os.path.abspath(dest))
1710
source = os.path.normpath(os.path.abspath(source))
1711
dest_parts = dest.strip(os.path.sep).split(os.path.sep)
1712
source_parts = source.strip(os.path.sep).split(os.path.sep)
1713
while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
1716
full_parts = ['..']*len(source_parts) + dest_parts
1717
if not dest_is_directory:
1718
full_parts.append(dest_filename)
1720
# Special case for the current directory (otherwise it'd be '')
1722
return os.path.sep.join(full_parts)
1726
############################################################
1727
## Bootstrap script creation:
1729
def create_bootstrap_script(extra_text, python_version=''):
1731
Creates a bootstrap script, which is like this script but with
1732
extend_parser, adjust_options, and after_install hooks.
1734
This returns a string that (written to disk of course) can be used
1735
as a bootstrap script with your own customizations. The script
1736
will be the standard virtualenv.py script, with your extra text
1737
added (your extra text should be Python code).
1739
If you include these functions, they will be called:
1741
``extend_parser(optparse_parser)``:
1742
You can add or remove options from the parser here.
1744
``adjust_options(options, args)``:
1745
You can change options here, or change the args (if you accept
1746
different kinds of arguments, be sure you modify ``args`` so it is
1747
only ``[DEST_DIR]``).
1749
``after_install(options, home_dir)``:
1751
After everything is installed, this function is called. This
1752
is probably the function you are most likely to use. An
1755
def after_install(options, home_dir):
1756
subprocess.call([join(home_dir, 'bin', 'easy_install'),
1758
subprocess.call([join(home_dir, 'bin', 'my-package-script'),
1761
This example immediately installs a package, and runs a setup
1762
script from that package.
1764
If you provide something like ``python_version='2.4'`` then the
1765
script will start with ``#!/usr/bin/env python2.4`` instead of
1766
``#!/usr/bin/env python``. You can use this when the script must
1767
be run with a particular Python version.
1770
if filename.endswith('.pyc'):
1771
filename = filename[:-1]
1772
f = codecs.open(filename, 'r', encoding='utf-8')
1775
py_exe = 'python%s' % python_version
1776
content = (('#!/usr/bin/env %s\n' % py_exe)
1777
+ '## WARNING: This file is generated\n'
1779
return content.replace('##EXT' 'END##', extra_text)
1784
b = base64.b64decode(s.encode('ascii'))
1785
return zlib.decompress(b).decode('utf-8')
1788
SITE_PY = convert("""
1789
eJzFPf1z2zaWv/OvwMqTIZXKdD66nR2n7o2TOK333MTbpLO5dT1aSoIs1hTJEqRl7c3d337vAwAB
1790
kvLHpp3TdGKJBB4eHt43HtDRaHRcljJfiHWxaDIplEyq+UqUSb1SYllUol6l1WK/TKp6C0/n18mV
1791
VKIuhNqqGFvFQfD0Cz/BU/FplSqDAnxLmrpYJ3U6T7JsK9J1WVS1XIhFU6X5lUjztE6TLP0XtCjy
1792
WDz9cgyC01zAzLNUVuJGVgrgKlEsxfm2XhW5iJoS5/w8/nPycjwRal6lZQ0NKo0zUGSV1EEu5QLQ
1793
hJaNAlKmtdxXpZyny3RuG26KJluIMkvmUvzznzw1ahqGgSrWcrOSlRQ5IAMwJcAqEQ/4mlZiXixk
1794
LMRrOU9wAH7eEitgaBNcM4VkzAuRFfkVzCmXc6lUUm1FNGtqAkQoi0UBOKWAQZ1mWbApqms1hiWl
1795
9djAI5Ewe/iTYfaAeeL4fc4BHD/kwc95ejth2MA9CK5eMdtUcpneigTBwk95K+dT/SxKl2KRLpdA
1796
g7weY5OAEVAiS2cHJS3Ht3qFvjsgrCxXJjCGRJS5Mb+kHnFwWoskU8C2TYk0UoT5WzlLkxyokd/A
1797
cAARSBoMjbNIVW3HodmJAgBUuI41SMlaiWidpDkw64/JnND+e5ovio0aEwVgtZT4tVG1O/9ogADQ
1798
2iHAJMDFMqvZ5Fl6LbPtGBD4BNhXUjVZjQKxSCs5r4sqlYoAAGpbIW8B6YlIKqlJyJxp5HZC9Cea
1799
pDkuLAoYCjy+RJIs06umIgkTyxQ4F7ji3YefxNuT16fH7zWPGWAss1drwBmg0EI7OMEA4qBR1UFW
1800
gEDHwRn+EcligUJ2heMDXm2Dg3tXOohg7mXc7eMsOJBdL64eBuZYgzKhsQLq99/QZaJWQJ//uWe9
1801
g+B4F1Vo4vxtsypAJvNkLcUqYf5Czgi+1XC+i8t69Qq4QSGcGkilcHEQwRThAUlcmkVFLkUJLJal
1802
uRwHQKEZtfVXEVjhfZHv01p3OAEgVEEOL51nYxoxlzDRPqxXqC9M4y3NTDcJ7Dqvi4oUB/B/Pidd
1803
lCX5NeGoiKH420xepXmOCCEvBOFeSAOr6xQ4cRGLM2pFesE0EiFrL26JItEALyHTAU/K22RdZnLC
1804
4ou69W41QoPJWpi1zpjjoGVN6pVWrZ3qIO+9iD93uI7QrFeVBODNzBO6ZVFMxAx0NmFTJmsWr3pT
1805
EOcEA/JEnZAnqCX0xe9A0WOlmrW0L5FXQLMQQwXLIsuKDZDsMAiE2MNGxij7zAlv4R38C3Dx30zW
1806
81UQOCNZwBoUIr8LFAIBkyBzzdUaCY/bNCt3lUyas6YoqoWsaKiHEfuAEX9gY5xr8L6otVHj6eIq
1807
F+u0RpU00yYzZYuXhzXrx1c8b5gGWG5FNDNNWzqtcXpZuUpm0rgkM7lESdCL9MouO4wZDIxJtrgW
1808
a7Yy8A7IIlO2IMOKBZXOspbkBAAMFr4kT8smo0YKGUwkMNC6JPjrBE16oZ0lYG82ywEqJDbfc7A/
1809
gNu/QIw2qxToMwcIoGFQS8HyzdK6Qgeh1UeBb/RNfx4fOPV0qW0TD7lM0kxb+SQPTunhSVWR+M5l
1810
ib0mmhgKZpjX6Npd5UBHFPPRaBQExh3aKvO1UEFdbQ+BFYQZZzqdNSkavukUTb3+oQIeRTgDe91s
1811
OwsPNITp9B6o5HRZVsUaX9u5fQRlAmNhj2BPnJOWkewge5z4CsnnqvTSNEXb7bCzQD0UnP908u70
1812
88lHcSQuWpU26eqzSxjzJE+ArckiAFN1hm11GbRExZei7hPvwLwTU4A9o94kvjKpG+BdQP1T1dBr
1813
mMbcexmcvD9+fXYy/fnjyU/Tj6efTgBBsDMy2KMpo3lswGFUMQgHcOVCxdq+Br0e9OD18Uf7IJim
1814
alpuyy08AEMJLFxFMN+JCPHhVNvgaZovi3BMjX9lJ/yI1Yr2uC4Ov74UR0ci/DW5ScIAvJ62KS/i
1815
jyQAn7alhK41/IkKNQ6ChVyCsFxLFKnoKXmyY+4ARISWhbasvxZpbt4zH7lDkMRH1ANwmE7nWaIU
1816
Np5OQyAtdRj4QIeY3WGUkwg6llu361ijgp9KwlLk2GWC/wygmMyoH6LBKLpdTCMQsPU8UZJb0fSh
1817
33SKWmY6jfSAIH7E4+AiseIIhWmCWqZKwRMlXkGtM1NFhj8RPsotiQwGQ6jXcJF0sBPfJFkjVeRM
1818
CogYRR0yompMFXEQOBUR2M526cbjLjUNz0AzIF9WgN6rOpTDzx54KKBgTNiFoRlHS0wzxPSvHBsQ
1819
DuAkhqiglepAYX0mzk/OxctnL/bRAYEocWGp4zVHm5rmjbQPl7BaV7J2EOZe4YSEYezSZYmaEZ8e
1820
3g1zHduV6bPCUi9xJdfFjVwAtsjAziqLn+gNxNIwj3kCqwiamCw4Kz3j6SUYOfLsQVrQ2gP11gTF
1821
rL9Z+j0O32WuQHVwKEyk1nE6G6+yKm5SdA9mW/0SrBuoN7RxxhUJnIXzmAyNGGgI8FtzpNRGhqDA
1822
qoZdTMIbQaKGX7SqMCZwZ6hbL+nrdV5s8inHrkeoJqOxZV0ULM282KBdgj3xDuwGIFlAKNYSjaGA
1823
ky5QtvYBeZg+TBcoS9EAAALTrCjAcmCZ4IymyHEeDoswxq8ECW8l0cLfmCEoODLEcCDR29g+MFoC
1824
IcHkrIKzqkEzGcqaaQYDOyTxue4s5qDRB9ChYgyGLtLQuJGh38UhKGdx5iolpx/a0M+fPzPbqBVl
1825
RBCxGU4ajf6SzFtcbsEUpqATjA/F+RVigw24owCmUZo1xf5HUZTsP8F6nmvZBssN8Vhdl4cHB5vN
1826
Jtb5gKK6OlDLgz//5Ztv/vKMdeJiQfwD03GkRSfH4gN6hz5o/K2xQN+ZlevwY5r73EiwIkl+FDmP
1827
iN/3TbooxOH+2OpP5OLWsOK/xvkABTI1gzKVgbajFqMnav9J/FKNxBMRuW2jMXsS2qRaK+ZbXehR
1828
F2C7wdOYF01eh44iVeIrsG4QUy/krLkK7eCejTQ/YKoop5Hlgf3nl4iBzxmGr4wpnqKWILZAi++Q
1829
/idmm4T8Ga0hkLxoonrx7nZYixniLh4u79Y7dITGzDBVyB0oEX6TBwugbdyXHPxoZxTtnuOMmo9n
1830
CIylDwzzalcwQsEhXHAtJq7UOVyNPipI04ZVMygYVzWCgga3bsbU1uDIRoYIEr0bE57zwuoWQKdO
1831
rs9E9GYVoIU7Ts/adVnB8YSQB47Ec3oiwak97L17xkvbZBmlYDo86lGFAXsLjXa6AL6MDICJGFU/
1832
j7ilCSw+dBaF12AAWMFZG2SwZY+Z8I3rA472RgPs1LP6u3ozjYdA4CJFnD16EHRC+YhHqBRIUxn5
1833
PXexuCVuf7A7LQ4xlVkmEmm1Q7i6ymNQqO40TMs0R93rLFI8zwrwiq1WJEZq3/vOAkUu+HjImGkJ
1834
1GRoyeE0OiJvzxPAULfDhNdVg6kBN3OCGK1TRdYNybSCf8CtoIwEpY+AlgTNgnmolPkT+x1kzs5X
1835
f9nBHpbQyBBu011uSM9iaDjm/Z5AMur8CUhBDiTsCyO5jqwOMuAwZ4E84YbXcqd0E4xYgZw5FoTU
1836
DOBOL70AB5/EuGdBEoqQb2slS/GVGMHydUX1Ybr7d+VSkzaInAbkKuh8w5Gbi3DyEEedvITP0H5G
1837
gnY3ygI4eAYuj5uad9ncMK1Nk4Cz7ituixRoZMqcjMYuqpeGMG76909HTouWWGYQw1DeQN4mjBlp
1838
HNjl1qBhwQ0Yb827Y+nHbsYC+0ZhoV7I9S3Ef2GVqnmhQgxwe7kL96O5ok8bi+1ZOhvBH28BRuNL
1839
D5LMdP4Csyz/xiChBz0cgu5NFtMii6TapHlICkzT78hfmh4elpSekTv4SOHUAUwUc5QH7yoQENqs
1840
PABxQk0AUbkMlXb7+2DvnOLIwuXuI89tvjh8edkn7mRXhsd+hpfq5LauEoWrlfGisVDgavUNOCpd
1841
mFySb/V2o96OxjChKhREkeLDx88CCcGZ2E2yfdzUW4ZHbO6dk/cxqINeu5dcndkRuwAiqBWRUQ7C
1842
x3Pkw5F97OTumNgjgDyKYe5YFANJ88m/A+euhYIx9hfbHPNoXZWBH3j9zdfTgcyoi+Q3X4/uGaVD
1843
jCGxjzqeoB2ZygDE4LRNl0omGfkaTifKKuYt79g25ZgVOsV/mskuB5xO/Jj3xmS08HvNe4Gj+ewR
1844
PSDMLma/QrCqdH7rJkkzSsoDGvv7qOdMnM2pg2F8PEh3o4w5KfBYnk0GQyF18QwWJuTAftyfjvaL
1845
jk3udyAgNZ8yUX1U9vQGfLt/5G2qu3uHfajamBgeesaZ/hcDWsKb8ZBd/xINh5/fRRlYYB4NRkNk
1846
9xzt/+9ZPvtjJvnAqZht39/RMD0S0O81E9bjDE3r8XHHIA4tu2sCDbAHWIodHuAdHlp/aN7oWxo/
1847
i1WSEk9Rdz0VG9rrpzQnbtoAlAW7YANwcBn1jvGbpqp435dUYCmrfdzLnAgsczJOGFVP9cEcvJc1
1848
YmKbzSlt7BTFFENqJNSJYDuTsHXhh+VsVZj0kcxv0gr6gsKNwh8+/HgS9hlAD4OdhsG562i45OEm
1849
HOE+gmlDTZzwMX2YQo/p8u9LVTeK8AlqttNNclaTbdA++DlZE9IPr8E9yRlv75T3qDFYnq/k/Hoq
1850
ad8d2RS7OvnpN/gaMbHb8X7xlEqWVAEGM5lnDdKKfWAs3Vs2+Zy2KmoJro6us8W6G9pN50zcMkuu
1851
RESdF5gF0txIiaKbpNKOYFkVWNkpmnRxcJUuhPytSTKMsOVyCbjgPpJ+FfPwlAwSb7kggCv+lJw3
1852
VVpvgQSJKvQ2HNUOOA1nW55o5CHJOy5MQKwmOBQfcdr4ngm3MOQycbq/+YCTxBAYO5h9UuQueg7v
1853
82KKo06pQHbCSPW3yOlx0B2hAAAjAArzH411Es1/I+mVu9dHa+4SFbWkR0o36C/IGUMo0RiTDvyb
1854
fvqM6PLWDiyvdmN5dTeWV10srwaxvPKxvLobS1ckcGFt/shIwlAOqbvDMFis4qZ/eJiTZL7idlg4
1855
iQWSAFGUJtY1MsX1w16SibfaCAipbWfvlx62xScpV2RWBWejNUjkftxP0nG1qfx2OlMpi+7MUzHu
1856
7K4CHL/vQRxTndWMurO8LZI6iT25uMqKGYitRXfSApiIbi0Opy3zm+mME60dSzU6/69PP3x4j80R
1857
1MhUGlA3XEQ0LDiV6GlSXam+NLVxWAnsSC39mhjqpgHuPTDJxaPs8T9vqdgCGUdsqFigECV4AFQS
1858
ZZu5hUNh2HmuK4z0c2Zy3vc5EqO8HrWT2kGk4/Pzt8efjkeUfRv978gVGENbXzpcfEwL26Dvv7nN
1859
LcWxDwi1TjO1xs+dk0frliPut7EGbM+H7zx48RCDPRix+7P8QykFSwKEinUe9jGEenAM9EVhQo8+
1860
hhF7lXPuJhc7K/adI3uOi+KI/tAOQHcAf98RY4wpEEC7UJGJDNpgqqP0rXm9g6IO0Af6el8cgnVD
1861
r24k41PUTmLAAXQoa5vtdv+8LRM2ekrWr0++P31/dvr6/PjTD44LiK7ch48HL8TJj58FlWqgAWOf
1862
KMEqhRqLgsCwuKeExKKA/xrM/CyamvO10Ovt2ZneNFnjOREsHEabE8Nzriiy0Dh9xQlh+1CXAiFG
1863
mQ6QnAM5VDlDB3YwXlrzYRBV6OJiOuczQ2e10aGXPmhlDmTRFnMM0geNXVIwCK72gldUAl6bqLDi
1864
zTh9SGkAKW2jbY1GRum53s69sxVlNjq8nCV1hidtZ63oL0IX1/AyVmWWQiT3KrSypLthpUrLOPqh
1865
3WtmvIY0oNMdRtYNedY7sUCr9Srkuen+45bRfmsAw5bB3sK8c0mVGlS+jHVmIsRGvKkSylv4apde
1866
r4GCBcM9txoX0TBdCrNPILgWqxQCCODJFVhfjBMAQmcl/Nz8oZMdkAUWSoRv1ov9v4WaIH7rX34Z
1867
aF5X2f4/RAlRkOCqnnCAmG7jtxD4xDIWJx/ejUNGjqpkxd8arK0Hh4QSoI60UykRb2ZPIyWzpS71
1868
8PUBvtB+Ar3udK9kWenuw65xiBLwREXkNTxRhn4hVl5Z2BOcyrgDGo8NWMzw+J1bEWA+e+LjSmaZ
1869
LhY/fXt2Ar4jnmRACeItsBMYjvMluJut6+D4eGAHFO51w+sK2bhCF5bqHRax12wwaY0iR729Egm7
1870
TpQY7vfqZYGrJFUu2hFOm2GZWvwYWRnWwiwrs3anDVLYbUMUR5lhlpieV1RL6vME8DI9TTgkglgJ
1871
z0mYDDxv6KZ5bYoHs3QOehRULijUCQgJEhcPAxLnFTnnwItKmTNE8LDcVunVqsZ9Bugc0/kFbP7j
1872
8eez0/dU0//iZet1DzDnhCKBCddzHGG1HmY74ItbgYdcNZ0O8ax+hTBQ+8Cf7isuFDniAXr9OLGI
1873
f7qv+BDXkRMJ8gxAQTVlVzwwAHC6DclNKwuMq42D8eNW47WY+WAoF4lnRnTNhTu/Pifalh1TQnkf
1874
8/IRGzjL0laH6c5udVj3o+e4LHHHaRENN4K3Q7JlPjPoet17s6sOzf30pBDPkwJG/db+GKZQq9dU
1875
T8dhtl3cQmGttrG/5E6u1Gk3z1GUgYiR23nsMtmwEtbNmQO9iuYeMPGtRtdI4qAqH/2Sj7SH4WFi
1876
id2LU0xHOlFCRgAzGVIfnGnAh0KLAAqECnEjR3In46cvvDk61uD+OWrdBbbxB1CEuiyWjlsUFXAi
1877
fPmNHUd+RWihHj0UoeOp5DIvbMkWfjYr9Cqf+3MclAFKYqLYVUl+JSOGNTEwv/KJvSMFS9rWI/VF
1878
ejlkWMQpOKe3Ozi8LxfDGycGtQ4j9Npdy21XHfnkwQaDpzLuJJgPvko2oPvLpo54JYdFfvgg2m6o
1879
90PEQkBoqvfBoxDTMb+FO9anBTxIDQ0LPbzfduzC8toYR9bax84Bo9C+0B7svILQrFa0LeOc7DO+
1880
qPUCWoN71Jr8kX2qa3bs74EjW05OyALlwV2Q3txGukEnnTDik0N87DKlyvT2YIt+t5A3MgOjAUY2
1881
woMHv9qDB+PYplMGS7K+GLvz7fl2GDd602J2aE5GoGemSli/OJf1AaIzmPG5C7MWGVzqX3RIkuTX
1882
5CW/+fvpRLx5/xP8+1p+AFOKJwcn4h+AhnhTVBBf8tFXupMAD1XUHDgWjcLjhQSNtir4+gZ02849
1883
OuO2iD7t4R/zsJpSYIFrteY7QwBFniAdB2/9BHOGAX6bQ1Ydb9R4ikOLMtIvkQa7z53gWY0D3TJe
1884
1esM7YWTJWlX82J0dvrm5P3Hk7i+RQ43P0dOFsWvjcLp6D3iCvfDJsI+mTf45NJxnH+QWTngN+ug
1885
05xhwaBThBCXlDbQ5PsoEhtcJBVmDkS5XRTzGFsCy/OxuXoDjvTYiS/vNfSelUVY0VjvorXePD4G
1886
aohfuopoBA2pj54T9SSEkhme3+LH8WjYFE8Epbbhz9PrzcLNjOuDODTBLqbtrCO/u9WFK6azhmc5
1887
ifA6sstgzmZmaaLWs7l7Zu9DLvR1IqDlaJ9DLpMmq4XMQXIpyKd7HUDTu8fsWEKYVdic0dkzStNk
1888
m2SrnCKkRIkRjjqio+m4IUMZQ4jBf0yu2R7g+T/R8EFigE6IUvxUOF1VM1+xBHNIRNQbKDzYpPlL
1889
t55HU5gH5Qh53jqyME90GxmjK1nr+fODaHzxvK10oKz03DtkOy/B6rlssgeqs3z69OlI/Mf93g+j
1890
EmdFcQ1uGcAe9FrO6PUOy60nZ1er79mbNzHw43wlL+DBJWXP7fMmp9TkHV1pQaT9a2CEuDahZUbT
1891
vmOXOWlX8UYzt+ANK205fs5TujQIU0sSla2+ewnTTkaaiCVBMYSJmqdpyGkKWI9t0eD5OEwzan6R
1892
t8DxKYKZ4FvcIeNQe4UeJtWyWu6x6ByJEQEeUW0Zj0YHjOmEGOA5Pd9qNKeneVq3RzueuZun+iB9
1893
be8C0nwlkg1KhplHhxjOUUuPVVsPu7iTRb2IpZhfuAnHziz59X24A2uDpBXLpcEUHppFmheymhtz
1894
iiuWztPaAWPaIRzuTFcgkfWJgwGURqDeySosrETbt3+y6+Ji+oH2kffNSLp8qLbXSnFyKMk7BYZx
1895
3I5PaShLSMu35ssYRnlPaW3tCXhjiT/ppCrW9Xu3X7hHDJtc32rB9RvtVRcAh25SsgrSsqOnI5zr
1896
uyx8Ztodd1Hgh0J0wu0mreomyab68oQpOmxTu7Gu8bRH0+48dGm9FXDyC/CA93UVPTgOpsoG6YlF
1897
sOaUxJFY6hRF7J728g9GlQV6eS/YVwKfAimzmJozyiaJdGHZ1R7+1DWbjopHUF+ZA0U7PHNzkqV3
1898
CMTFfEJ1TuYIwg4v2uDSvVNCfHckoucT8edOIDQvt3grEqD8ZBE/WYS+T0ZdLw5ftHamH3h2IOwE
1899
8vLy0dPN0hlNLxwq/76/ry46xABwDbKzTOVi/4lC7BjnL4WqobTz2s0pNGM8Hb5nq570wej2uAid
1900
CpuBV79pFYqjWoz/aQcxJ661HuDDqSi0bIHsgXpTeNIp/rOXnmFhoEbPX1n0XKZDm1P4DS8ugfea
1901
oK6js3PTUle4W7ADMbk+xshbUG3DluPv9ageJUrdGvFeK9yebCXOZf1H8HBIl7wQ03zV2Rb+I5mH
1902
i/Z3bS72sPzm67vwdBXM4ImFgQX1FtNp9Qcy9U6WfezCPGC//n7+fzjv38X3j6aS7jVMKwylsJB5
1903
lfAbNIlNeWhTDUYl4FZQ5Ja34ae+HjwTw+oAdWN9Hd41fe5/19x1i8DO3Ozu9ubun31zaaD77uaX
1904
IRpwmKcJ8aCa8VZgh3WBK8YTXVQwnLLUHyS/2wlnukMr3AfGlDBgApTYVGNvtPY6mbvfsUJmn693
1905
dY86DtqKzrR7Zz+7HP8QRc/VAPjcnn6mEo+F5kD2G+m+rikXDU7l1ZWaJnhX3JSCDSpw6XmRxn19
1906
R1d9yURtjdeJF6oACMNNuhTRrTYGxoCAhu+s5foQ5+YMQUNTFaVTlqnSBWeQtIsL4GLOHFF/k5nk
1907
uspRJjHhp5qqrCAqGOmbTblwYajWswVqEhnrRF0b1E2Pib7oEofgahlzPJLzVRxpeNQBQvCpKefa
1908
Ji5Unk7tO+CXZ+0x8HRiGULmzVpWSd1egeJvk6biO2cEOhSLC+ykKlrJ7HCKi1hq+cNBCpMF9vtX
1909
2sn2gow7zn6PrdZ7OFtRD50Ce8yxcsf2GG5Ob+0VaO7VOwu6MNc18rZZy3322hdYCnOfF+lKnTvg
1910
t/qOIb65kjOb6CY4fARy7x5J88tzrVpjJ8Wi4TxzFUP/Uhk81Uy2eOiuuB4X9G+F6wQadnxfb1hm
1911
6YUmOxpbKmrXalDxtKON24gaK+nuiaj9aulHRtQe/AdG1PpmPzA4Gh+tDwbrp+8JvVlNuNfktYwA
1912
faZAJNzZ61yyZkxm5FYjQ9ib3o7sNbWsM50jTsZMIEf2708iEHwdnnJLN73rqu6KqH3posffn314
1913
fXxGtJieH7/5z+PvqVoF08cdm/XglENe7DO19726WDf9oCsMhgZvsR24d5IPd2gIvfe9zdkBCMMH
1914
eYYWtKvI3Ne7OvQORPQ7AeJ3T7sDdZfKHoTc88908b1bV9ApYA30U642NL+cLVvzyOxcsDi0OxPm
1915
fZtM1jLay7XtWjin7q+vTrTfqm8q3JEHHNvqU1oBzCEjf9kUsjlKYBOV7Kh0/+cBVDKLx7DMLR8g
1916
hXPp3DZHF80xqNr/vxRUoOwS3Adjh3Fib/yldpwuV/Yqa9wLm8vYEMQ7BzXqz88V9oXMdlAhCFjh
1917
6bvUGBGj//QGk92OfaLExT6duNxHZXNpf+GaaSf37yluutb2TiLFlRu87QSNl03mbqTaPr0O5PxR
1918
dr5YOiX+oPkOgM6teCpgb/SZWCHOtiKEQFJvGGLVINFRXyjmII9208He0OqZ2N91Hs89jybE890N
1919
F50jb7rHC+6h7umhGnPqybHAWL6266Cd+I4g8/aOoEuIPOcD9xT13bfw9ebi+aFNtiK/42tHkVCZ
1920
zcgx7BdOmdqdF9853YlZqgnVMWHM5hzT1C0uHajsE+yKcXq1+jviILPvy5BG3vvhIh/Tw7vQe9TF
1921
1LLeIUxJRE/UmKblnG7QuNsn4/50W7XVB8InNR4ApKcCARaC6elGp3Juy+Wv0TMdFc4aujLUzbiH
1922
jlRQFY3PEdzD+H4tft3udMLyQd0ZRdOfG3Q5UC85CDf7Dtxq7KVEdpuE7tRbPtjhAvBh1eH+zx/Q
1923
v1/fZbu/uMuvtq1eDh6QYl8WSwKxUqJDIvM4BiMDejMibY115EbQ8X6Olo4uQ7VzQ75Ax4/KDPFC
1924
YAowyJmdag/AGoXg/wBaZusT
1928
EZ_SETUP_PY = convert("""
1929
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
1995
BDaonX65d/fwEjNqlDjLVIvM9X+XVxF7
1998
##file distribute_setup.py
1999
DISTRIBUTE_SETUP_PY = convert("""
2000
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
2085
ACTIVATE_SH = convert("""
2086
eJytVVFv2jAQfs+vuIY+lGo06h5bMYmqSCC1UDWs09ZWwSQOseTYKHZI6bT/vnMSQtIA0rTmgRDf
2087
57vPd9+dOzCLmIKQcQpxqjQsKKSKBpAxHYGtZJr4FBZMOMTXbE00teE8TGQMC6Kic6sDG5mCT4SQ
2088
GpJUANMQsIT6mm8sK6DbXXDWhd8W4JMKRTWsNoH0rXyhAwk1S5IHQMWaJVLEVGhYk4SRBacqR7EQ
2089
nqEnwD71pne33tP4cfZ9cOc9DGYjG17hGnRERY40j1nu74NWCPq2konOgdVaQa21KbeH7CiNn7PR
2090
dDKa3g/3kamMLUq7bS1ilekovSYKSZYpzauqIpliUgOqsR55wYCIAN5V9AWyiPkRRGRNgeALTb6M
2091
Y2PWEdG5FkpXqAifcI6a0BKWyABLjP9CmZiPFUHRlFvVBcAP1I1MdWnWTCxLNw2gSRCcmuSCHxGx
2092
pAoyFCAJzM8GjJgwLOpihcxp8CH1NwMXi96Txdcvd+Q9DR/d8XSyJ/n50XoJfP3mBHTtiJTzRqoO
2093
FdS93FdJ97JVQgS2audeHi1aad5SKCBb63DytCN2gryQSB9sIUVAlU5S01D0A7cOuJSHsAWcfIje
2094
M6ZtJ25D/7GweQs7SxLKUQmNpqv1bjO2ZdWo9m3Pq316nm2VSaifx2r1FKax6Mfyo4Z2PO9mPPEm
2095
g/uh512VsHq7Vrx36jfZwhW0aCP8jHEOIWHcrNdRyqCMeo3+aLzSG8BzoUjhrGgIRCxIgG2yycim
2096
i/78vIVwJMIcfZ3l6Uyv4QrVW/ntwvUcmMg7zNoJ6uBQONDC/caWmjRqXW40U0R4h0bWvNuxO7i5
2097
G3oPj9P7h9nRiLmKK+Hm7uy3XR0LD1hKOOnD24EuaMN3HilXtOZ6jnmhgsQUXhqUX+x5Lm0TqRWk
2098
A6b3GeE4fDD5OE5ggCsC58OS+eUdIxNWXg/lFkoh0np15ThZll28U40TZX2BU8dRMtQZSahDjBen
2099
eZjnGsU5ut5L9mU+f4U9h6y8nB05aHe3sbxJyldtZJjaEs6IKm7Hvr3a4CwV0IuLBdso/1MG+ycM
2100
9f8c6P8+zPcNcszYX1+tk3g=
2103
##file activate.fish
2104
ACTIVATE_FISH = convert("""
2105
eJyVVWFv2jAQ/c6vuBoqQVWC9nVSNVGVCaS2VC2rNLWVZZILWAs2sx1Yq/342SEJDrjbmgpK7PP5
2106
3bt3d22YLbmGlGcIq1wbmCPkGhPYcrMEEsGciwGLDd8wg1HK9ZLAWarkCtzvM+gujVl/Hgzcm15i
2107
lkVSLXqtNrzKHGImhDSgcgHcQMIVxiZ7bbXSXFiPUkCClWuAfgJk9MvabbgyOctQbICJBBSaXAkw
2108
EoRUK5ZBcQ3Yba6kWKEwpAX2aVtLjQZklvibsGGKs3mGurDiKRi0YfYFkA6dXl/Rx8n97Nvwmt4N
2109
Z2MChZF7nKv+4he4ZTi2bNohhA1QJP+69ftsPL0dT29G5Pjqeu8QQL3xdxhNswrMO4i+Th7G9O5+
2110
enM3o9PH0f395MrDVKVMu1tcsunaimBtggBCrmrDCLpWZAsu6pXqWSsuTAqklod3z7N4Nm1ydGQP
2111
i9q80xCwMnT4DWudz6EXDil4vMFYGWBF7uj2sUEk6TC12Dx9eiFwcgFESJHYZZU7feMeeBseMEuh
2112
2jsJo9nXRY3DfWxZ5cLh4EphxjZNeXvF1Ly91aoU5YEHQqn3SinZmx2JGTqFpBs1QTre8QGll5Nb
2113
eju8GVlPpXkN1xOypcuutHb/oP8TDkQahuAVQsgefS8FUbW835o46dXkYXh5PSrVWXUOl3jX9jSw
2114
OhHAhTbIEpCp7UOupTiuXR9aoEDlaDZLhJ1cor1O2qBtZoq9OLd5sjnydLV3z3RhU78HFRgulqNC
2115
OTwbqJa9vkJFclQgZSjFFHAwpeIWhe2+h2HYANkKk3PYouv3IDeoFE9wd1TmCuRW7OgJ1bVXGHc7
2116
z5WDL/WW36v2oi37CyVBak61+yPBA9C1qqGxzKQqZ0oPuocU9hpud0PIp8sDHkXR1HKktlzjuUWA
2117
a0enFUyzOWZA4yXGP+ZMI3Tdt2OuqU/SO4q64526cPE0A7ZyW2PMbWZiZ5HamIZ2RcCKLXhcDl2b
2118
vXL+eccQoRze2+02ekPDEtxEsVwNtEzNlikcMOdp8A7BT6f65VSDY9kjtD+HeZbb9C+5wZ4XZ9dC
2119
CQXc+2A6MNP4DqLuqe7t0v4/gA5wfBRGKQGX6oMhUbWv0Bg8uLXoVn8AkYzUxg==
2123
ACTIVATE_CSH = convert("""
2124
eJx9U11v2jAUffevOA2o3ZBG9gxjGx2VVqmlVUUrTWMyTnLTWEocZDsg+uvnOEDDx5aHKLn3fFyf
2125
3HQwy6RBKnNCURmLiFAZSrCWNkNgykrHhEiqUMRWroSlfmyyAL1UlwXcY6/POvhVVoiFUqWFrhSk
2126
RSI1xTbf1N0fmhwvQbTBRKxkQphIXOfCSHxJfCGJvr8WQub9uCy+9hkTuRQGCe08cWXJzdb9xh/u
2127
Jvzl9mn2PL7jj+PZT1yM8BmXlzBkSa3ga0H3BBfUmEo5FE56Q2jKhMmGOOvy9HD/OGv7YOnOvrSj
2128
YxsP/KeR7w6bVj3prnEzfdkaB/OLQS+onQJVqsSVdFUHQFvNk1Ra1eUmKeMr5tJ+9t5Sa8rFipTF
2129
SmgpopxMn7W4hw6MnU6FgPPWK+eBR53m54LwEbPDb9Dihpxf3075dHx/w/lgiz4j5jNyck3ADiJT
2130
fGiN0QDcJD6k4CNsRorBXbWW8+ZKFIQRznEY5YY8uFZdRMKQRx9MGiww8vS2eH11YJYUS5G7RTeE
2131
tNQYu4pCIV5lvN33UksybQoRMmuXgzBcr9f9N7IioVW95aEpU7sWmkJRq4R70tFB3secL5zHmYHn
2132
i4Un70/3X5WjwzZMlciUNff39a5T/N3difzB/qM0y71r7H5Wv4DubrNS4VPRvDPW/FmM/QUd6WEa
2136
ACTIVATE_BAT = convert("""
2137
eJyFUkEKgzAQvAfyhz0YaL9QEWpRqlSjWGspFPZQTevFHOr/adQaU1GaUzI7Mzu7ZF89XhKkEJS8
2138
qxaKMMsvboQ+LxxE44VICSW1gEa2UFaibqoS0iyJ0xw2lIA6nX5AHCu1jpRsv5KRjknkac9VLVug
2139
sX9mtzxIeJDE/mg4OGp47qoLo3NHX2jsMB3AiDht5hryAUOEifoTdCXbSh7V0My2NMq/Xbh5MEjU
2140
ZT63gpgNT9lKOJ/CtHsvT99re3pX303kydn4HeyOeAg5cjf2EW1D6HOPkg9NGKhu
2143
##file deactivate.bat
2144
DEACTIVATE_BAT = convert("""
2145
eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
2146
FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL
2147
i2dASrm4rFz9XLgAwJNbyQ==
2151
ACTIVATE_PS = convert("""
2152
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
2241
##file distutils-init.py
2242
DISTUTILS_INIT = convert("""
2243
eJytV92L4zYQf9dfMU0ottuse7RvC6FQrg8Lxz2Ugz4si9HacqKuIxlJ2ST313fG8odkO9d7qGFB
2244
keZLv/nNjFaeWm0caMukX9nbuLxwo6Q6WBg2dFvqSsB2WEgLSjvg8C6NO/NGqHc46erciB1YDRcB
2245
JVdwtijpwGmoparAHQVYVzXylUH0beGpc8OV+wG+oLo2b6AVtLf2tkM19HY6WwevAj16N7jLHRhh
2246
ZSUsSEXGF1bR00N7c0etfkEtWUtRPVzzW/4VKmlE6bS5MYZLxU8C9ghF3nJ3zPsdOrLu7GRjC9oP
2247
JP7RUqUz8dRDkxdFLRtRFNkOktFAkjFZj+pKmxMt0thBBvtFEOlCZ7SfPXYXHnKV0yIdMdh8QbSD
2248
7IyuoOXlGz8glA5+tMDbVnBjKUkIrwcSLAHS6JI7iWng1m/erBOnydDvm4yJxgofRtFdoShyqaww
2249
Lv2wg9ntOjFxFSUiJSb4OixjUUSuKKSSDs21tyTLciN4lWYZY7XRQQjQ05M2dhRgqVUtD4w5c/Nh
2250
vXIrrDMIEBPXUrQOPuPd/jRGm7kA5hcXjG23CJErj/B6lk1ViKuDKT6otLAqcfCm9AWO+IfAHYTr
2251
EEK+2YBa3tCRmHxB/uuLhQeqhyM3FVHFw0oimAajz32JdM5FRdfJWyNqecV7I3u63w13NTKBmJKg
2252
0d9+Tfw1YlzyUp9OXFX5dIUeqWkDs6pxOW50ZsqGWzsJpZFETzj6KlFTTfNGfhWFbokmFlIrmjoQ
2253
oo/ixt0coTHc3ApEx1L3+KyVeJwVLKyI7uH5JRITDZqUFlmG7aIU6UJlF6Q0+z4Xi73cto10A0Wt
2254
aLPIDvumwaACIo5T/pDHTeGTuoPNJ+TLJottR4jnc4w9xMtg1tO/mvTxR9F3Ul8Gs92AOfvpsCuO
2255
yQ2terraR8YodGr0ha/Crk8RvCSWf5SUktczXSNfSLGeUPFuSKi6q489rDoJYPFdqpgKdta1F50m
2256
QK0+JN7INmjW4ooCNp3b7cPajrEFaV/Ijgnbwt80t7BnlLxpfLkL84CD0oC/ENCFWF86GIOfTVjt
2257
rbbymkyEJp3u9v302mCrjO6y8Q137NCrSqs6c6kFjQcGR4JZEHUnLi0dpbHQFAv2MeyGOFFw6DQY
2258
RNrBuOwfJJMLVdmLxPGXzCJOVmrc58OIk34XKalnLD6ioaeqdCV8I9zZKC/GvoO4iM6SzHGVjGNp
2259
Vio4NQr/OsFZV1IbGgTz+KgrjvFwppfSSChsK0p835R7ZJ9Pzp46bI8Ngug3l5233++ch90pBGMZ
2260
bOx0cJmxe0Hio6jSZVH09bt+yO7dP4RmprtAEhvxPSTp3XkXSTxcIkkjpsJhTad3kQ2FgJru/wj1
2261
Iqo4pv8AHiXuAx8crgM/Q3KmOwHfH79zP0ojU8HZCvTBafoTN4ehp3bY9PZWvPSyI/7fehbRh9HS
2262
XF7rY/E4brpxPOrF74wxKHrXli7rUp18evrj49NfSffPELaxUSjuSeP286DwgtEMcW1xKr/he4/6
2263
IQ6FUXP+0gkioHY5iwC9Eyx3HKO7af0zPPe+XyLnZDUk46jB7uZthV8rp+wuKxYMCxnzL9Vk9s4=
2266
##file distutils.cfg
2267
DISTUTILS_CFG = convert("""
2268
eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
2269
xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
2270
9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
2273
##file activate_this.py
2274
ACTIVATE_THIS = convert("""
2275
eJyNU01v2zAMvetXEB4K21jmDOstQA4dMGCHbeihlyEIDMWmG62yJEiKE//7kXKdpN2KzYBt8euR
2276
fKSyLPs8wiEo8wh4wqZTGou4V6Hm0wJa1cSiTkJdr8+GsoTRHuCotBayiWqQEYGtMCgfD1KjGYBe
2277
5a3p0cRKiAe2NtLADikftnDco0ko/SFEVgEZ8aRC5GLux7i3BpSJ6J1H+i7A2CjiHq9z7JRZuuQq
2278
siwTIvpxJYCeuWaBpwZdhB+yxy/eWz+ZvVSU8C4E9FFZkyxFsvCT/ZzL8gcz9aXVE14Yyp2M+2W0
2279
y7n5mp0qN+avKXvbsyyzUqjeWR8hjGE+2iCE1W1tQ82hsCZN9UzlJr+/e/iab8WfqsmPI6pWeUPd
2280
FrMsd4H/55poeO9n54COhUs+sZNEzNtg/wanpjpuqHJaxs76HtZryI/K3H7KJ/KDIhqcbJ7kI4ar
2281
XL+sMgXnX0D+Te2Iy5xdP8yueSlQB/x/ED2BTAtyE3K4SYUN6AMNfbO63f4lBW3bUJPbTL+mjSxS
2282
PyRfJkZRgj+VbFv+EzHFi5pKwUEepa4JslMnwkowSRCXI+m5XvEOvtuBrxHdhLalG0JofYBok6qj
2283
YdN2dEngUlbC4PG60M1WEN0piu7Nq7on0mgyyUw3iV1etLo6r/81biWdQ9MWHFaePWZYaq+nmp+t
2284
s3az+sj7eA0jfgPfeoN1
2287
MH_MAGIC = 0xfeedface
2288
MH_CIGAM = 0xcefaedfe
2289
MH_MAGIC_64 = 0xfeedfacf
2290
MH_CIGAM_64 = 0xcffaedfe
2291
FAT_MAGIC = 0xcafebabe
2295
maxint = majver == 3 and getattr(sys, 'maxsize') or getattr(sys, 'maxint')
2298
class fileview(object):
2300
A proxy for file-like objects that exposes a given view of a file.
2301
Modified from macholib.
2304
def __init__(self, fileobj, start=0, size=maxint):
2305
if isinstance(fileobj, fileview):
2306
self._fileobj = fileobj._fileobj
2308
self._fileobj = fileobj
2310
self._end = start + size
2314
return '<fileview [%d, %d] %r>' % (
2315
self._start, self._end, self._fileobj)
2320
def _checkwindow(self, seekto, op):
2321
if not (self._start <= seekto <= self._end):
2322
raise IOError("%s to offset %d is outside window [%d, %d]" % (
2323
op, seekto, self._start, self._end))
2325
def seek(self, offset, whence=0):
2327
if whence == os.SEEK_SET:
2328
seekto += self._start
2329
elif whence == os.SEEK_CUR:
2330
seekto += self._start + self._pos
2331
elif whence == os.SEEK_END:
2334
raise IOError("Invalid whence argument to seek: %r" % (whence,))
2335
self._checkwindow(seekto, 'seek')
2336
self._fileobj.seek(seekto)
2337
self._pos = seekto - self._start
2339
def write(self, bytes):
2340
here = self._start + self._pos
2341
self._checkwindow(here, 'write')
2342
self._checkwindow(here + len(bytes), 'write')
2343
self._fileobj.seek(here, os.SEEK_SET)
2344
self._fileobj.write(bytes)
2345
self._pos += len(bytes)
2347
def read(self, size=maxint):
2349
here = self._start + self._pos
2350
self._checkwindow(here, 'read')
2351
size = min(size, self._end - here)
2352
self._fileobj.seek(here, os.SEEK_SET)
2353
bytes = self._fileobj.read(size)
2354
self._pos += len(bytes)
2358
def read_data(file, endian, num=1):
2360
Read a given number of 32-bits unsigned integers from the given file
2361
with the given endianness.
2363
res = struct.unpack(endian + 'L' * num, file.read(num * 4))
2369
def mach_o_change(path, what, value):
2371
Replace a given name (what) in any LC_LOAD_DYLIB command found in
2372
the given binary with a new name (value), provided it's shorter.
2375
def do_macho(file, bits, endian):
2376
# Read Mach-O header (the magic number is assumed read by the caller)
2377
cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = read_data(file, endian, 6)
2378
# 64-bits header has one more field.
2380
read_data(file, endian)
2381
# The header is followed by ncmds commands
2382
for n in range(ncmds):
2384
# Read command header
2385
cmd, cmdsize = read_data(file, endian, 2)
2386
if cmd == LC_LOAD_DYLIB:
2387
# The first data field in LC_LOAD_DYLIB commands is the
2388
# offset of the name, starting from the beginning of the
2390
name_offset = read_data(file, endian)
2391
file.seek(where + name_offset, os.SEEK_SET)
2392
# Read the NUL terminated string
2393
load = file.read(cmdsize - name_offset)
2394
load = load[:load.index('\0')]
2395
# If the string is what is being replaced, overwrite it.
2397
file.seek(where + name_offset, os.SEEK_SET)
2398
file.write(value + '\0')
2399
# Seek to the next command
2400
file.seek(where + cmdsize, os.SEEK_SET)
2402
def do_file(file, offset=0, size=maxint):
2403
file = fileview(file, offset, size)
2405
magic = read_data(file, BIG_ENDIAN)
2406
if magic == FAT_MAGIC:
2407
# Fat binaries contain nfat_arch Mach-O binaries
2408
nfat_arch = read_data(file, BIG_ENDIAN)
2409
for n in range(nfat_arch):
2411
cputype, cpusubtype, offset, size, align = read_data(file, BIG_ENDIAN, 5)
2412
do_file(file, offset, size)
2413
elif magic == MH_MAGIC:
2414
do_macho(file, 32, BIG_ENDIAN)
2415
elif magic == MH_CIGAM:
2416
do_macho(file, 32, LITTLE_ENDIAN)
2417
elif magic == MH_MAGIC_64:
2418
do_macho(file, 64, BIG_ENDIAN)
2419
elif magic == MH_CIGAM_64:
2420
do_macho(file, 64, LITTLE_ENDIAN)
2422
assert(len(what) >= len(value))
2423
do_file(open(path, 'r+b'))
2426
if __name__ == '__main__':
2430
## Copy python.exe.manifest
2431
## Monkeypatch distutils.sysconfig