aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSix <unknown>2010-12-11 18:47:55 -0500
committerSix <unknown>2010-12-11 18:47:55 -0500
commit88ad64b2ff37b4693f6823a9b553500db5fad9da (patch)
tree0295d0b41e4e7a54f69e9ed06c537a7bcc5bafe6
parent0f54ee4428ba4057a0d8ba56868278490efea71f (diff)
downloaddodai-macsupport-88ad64b2ff37b4693f6823a9b553500db5fad9da.tar.bz2
dodai-macsupport-88ad64b2ff37b4693f6823a9b553500db5fad9da.tar.xz
dodai-macsupport-88ad64b2ff37b4693f6823a9b553500db5fad9da.zip
new devstrap file
-rw-r--r--dodai-devstrap.py1771
1 files changed, 1771 insertions, 0 deletions
diff --git a/dodai-devstrap.py b/dodai-devstrap.py
new file mode 100644
index 0000000..48face5
--- /dev/null
+++ b/dodai-devstrap.py
@@ -0,0 +1,1771 @@
1#!/usr/bin/env python
2## WARNING: This file is generated
3#!/usr/bin/env python
4"""Create a "virtual" Python installation
5"""
6
7virtualenv_version = "1.5.1"
8
9import sys
10import os
11import optparse
12import re
13import shutil
14import logging
15import tempfile
16import distutils.sysconfig
17try:
18 import subprocess
19except ImportError, e:
20 if sys.version_info <= (2, 3):
21 print 'ERROR: %s' % e
22 print 'ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.'
23 print 'If you copy subprocess.py from a newer version of Python this script will probably work'
24 sys.exit(101)
25 else:
26 raise
27try:
28 set
29except NameError:
30 from sets import Set as set
31
32join = os.path.join
33py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
34
35is_jython = sys.platform.startswith('java')
36is_pypy = hasattr(sys, 'pypy_version_info')
37
38if is_pypy:
39 expected_exe = 'pypy-c'
40elif is_jython:
41 expected_exe = 'jython'
42else:
43 expected_exe = 'python'
44
45
46REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
47 'fnmatch', 'locale', 'encodings', 'codecs',
48 'stat', 'UserDict', 'readline', 'copy_reg', 'types',
49 're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
50 'zlib']
51
52REQUIRED_FILES = ['lib-dynload', 'config']
53
54if sys.version_info[:2] >= (2, 6):
55 REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
56if sys.version_info[:2] >= (2, 7):
57 REQUIRED_MODULES.extend(['_weakrefset'])
58if sys.version_info[:2] <= (2, 3):
59 REQUIRED_MODULES.extend(['sets', '__future__'])
60if is_pypy:
61 # these are needed to correctly display the exceptions that may happen
62 # during the bootstrap
63 REQUIRED_MODULES.extend(['traceback', 'linecache'])
64
65class Logger(object):
66
67 """
68 Logging object for use in command-line script. Allows ranges of
69 levels, to avoid some redundancy of displayed information.
70 """
71
72 DEBUG = logging.DEBUG
73 INFO = logging.INFO
74 NOTIFY = (logging.INFO+logging.WARN)/2
75 WARN = WARNING = logging.WARN
76 ERROR = logging.ERROR
77 FATAL = logging.FATAL
78
79 LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
80
81 def __init__(self, consumers):
82 self.consumers = consumers
83 self.indent = 0
84 self.in_progress = None
85 self.in_progress_hanging = False
86
87 def debug(self, msg, *args, **kw):
88 self.log(self.DEBUG, msg, *args, **kw)
89 def info(self, msg, *args, **kw):
90 self.log(self.INFO, msg, *args, **kw)
91 def notify(self, msg, *args, **kw):
92 self.log(self.NOTIFY, msg, *args, **kw)
93 def warn(self, msg, *args, **kw):
94 self.log(self.WARN, msg, *args, **kw)
95 def error(self, msg, *args, **kw):
96 self.log(self.WARN, msg, *args, **kw)
97 def fatal(self, msg, *args, **kw):
98 self.log(self.FATAL, msg, *args, **kw)
99 def log(self, level, msg, *args, **kw):
100 if args:
101 if kw:
102 raise TypeError(
103 "You may give positional or keyword arguments, not both")
104 args = args or kw
105 rendered = None
106 for consumer_level, consumer in self.consumers:
107 if self.level_matches(level, consumer_level):
108 if (self.in_progress_hanging
109 and consumer in (sys.stdout, sys.stderr)):
110 self.in_progress_hanging = False
111 sys.stdout.write('\n')
112 sys.stdout.flush()
113 if rendered is None:
114 if args:
115 rendered = msg % args
116 else:
117 rendered = msg
118 rendered = ' '*self.indent + rendered
119 if hasattr(consumer, 'write'):
120 consumer.write(rendered+'\n')
121 else:
122 consumer(rendered)
123
124 def start_progress(self, msg):
125 assert not self.in_progress, (
126 "Tried to start_progress(%r) while in_progress %r"
127 % (msg, self.in_progress))
128 if self.level_matches(self.NOTIFY, self._stdout_level()):
129 sys.stdout.write(msg)
130 sys.stdout.flush()
131 self.in_progress_hanging = True
132 else:
133 self.in_progress_hanging = False
134 self.in_progress = msg
135
136 def end_progress(self, msg='done.'):
137 assert self.in_progress, (
138 "Tried to end_progress without start_progress")
139 if self.stdout_level_matches(self.NOTIFY):
140 if not self.in_progress_hanging:
141 # Some message has been printed out since start_progress
142 sys.stdout.write('...' + self.in_progress + msg + '\n')
143 sys.stdout.flush()
144 else:
145 sys.stdout.write(msg + '\n')
146 sys.stdout.flush()
147 self.in_progress = None
148 self.in_progress_hanging = False
149
150 def show_progress(self):
151 """If we are in a progress scope, and no log messages have been
152 shown, write out another '.'"""
153 if self.in_progress_hanging:
154 sys.stdout.write('.')
155 sys.stdout.flush()
156
157 def stdout_level_matches(self, level):
158 """Returns true if a message at this level will go to stdout"""
159 return self.level_matches(level, self._stdout_level())
160
161 def _stdout_level(self):
162 """Returns the level that stdout runs at"""
163 for level, consumer in self.consumers:
164 if consumer is sys.stdout:
165 return level
166 return self.FATAL
167
168 def level_matches(self, level, consumer_level):
169 """
170 >>> l = Logger()
171 >>> l.level_matches(3, 4)
172 False
173 >>> l.level_matches(3, 2)
174 True
175 >>> l.level_matches(slice(None, 3), 3)
176 False
177 >>> l.level_matches(slice(None, 3), 2)
178 True
179 >>> l.level_matches(slice(1, 3), 1)
180 True
181 >>> l.level_matches(slice(2, 3), 1)
182 False
183 """
184 if isinstance(level, slice):
185 start, stop = level.start, level.stop
186 if start is not None and start > consumer_level:
187 return False
188 if stop is not None or stop <= consumer_level:
189 return False
190 return True
191 else:
192 return level >= consumer_level
193
194 #@classmethod
195 def level_for_integer(cls, level):
196 levels = cls.LEVELS
197 if level < 0:
198 return levels[0]
199 if level >= len(levels):
200 return levels[-1]
201 return levels[level]
202
203 level_for_integer = classmethod(level_for_integer)
204
205def mkdir(path):
206 if not os.path.exists(path):
207 logger.info('Creating %s', path)
208 os.makedirs(path)
209 else:
210 logger.info('Directory %s already exists', path)
211
212def copyfile(src, dest, symlink=True):
213 if not os.path.exists(src):
214 # Some bad symlink in the src
215 logger.warn('Cannot find file %s (bad symlink)', src)
216 return
217 if os.path.exists(dest):
218 logger.debug('File %s already exists', dest)
219 return
220 if not os.path.exists(os.path.dirname(dest)):
221 logger.info('Creating parent directories for %s' % os.path.dirname(dest))
222 os.makedirs(os.path.dirname(dest))
223 if symlink and hasattr(os, 'symlink'):
224 logger.info('Symlinking %s', dest)
225 os.symlink(os.path.abspath(src), dest)
226 else:
227 logger.info('Copying to %s', dest)
228 if os.path.isdir(src):
229 shutil.copytree(src, dest, True)
230 else:
231 shutil.copy2(src, dest)
232
233def writefile(dest, content, overwrite=True):
234 if not os.path.exists(dest):
235 logger.info('Writing %s', dest)
236 f = open(dest, 'wb')
237 f.write(content)
238 f.close()
239 return
240 else:
241 f = open(dest, 'rb')
242 c = f.read()
243 f.close()
244 if c != content:
245 if not overwrite:
246 logger.notify('File %s exists with different content; not overwriting', dest)
247 return
248 logger.notify('Overwriting %s with new content', dest)
249 f = open(dest, 'wb')
250 f.write(content)
251 f.close()
252 else:
253 logger.info('Content %s already in place', dest)
254
255def rmtree(dir):
256 if os.path.exists(dir):
257 logger.notify('Deleting tree %s', dir)
258 shutil.rmtree(dir)
259 else:
260 logger.info('Do not need to delete %s; already gone', dir)
261
262def make_exe(fn):
263 if hasattr(os, 'chmod'):
264 oldmode = os.stat(fn).st_mode & 07777
265 newmode = (oldmode | 0555) & 07777
266 os.chmod(fn, newmode)
267 logger.info('Changed mode of %s to %s', fn, oct(newmode))
268
269def _find_file(filename, dirs):
270 for dir in dirs:
271 if os.path.exists(join(dir, filename)):
272 return join(dir, filename)
273 return filename
274
275def _install_req(py_executable, unzip=False, distribute=False):
276 if not distribute:
277 setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3]
278 project_name = 'setuptools'
279 bootstrap_script = EZ_SETUP_PY
280 source = None
281 else:
282 setup_fn = None
283 source = 'distribute-0.6.14.tar.gz'
284 project_name = 'distribute'
285 bootstrap_script = DISTRIBUTE_SETUP_PY
286 try:
287 # check if the global Python has distribute installed or plain
288 # setuptools
289 import pkg_resources
290 if not hasattr(pkg_resources, '_distribute'):
291 location = os.path.dirname(pkg_resources.__file__)
292 logger.notify("A globally installed setuptools was found (in %s)" % location)
293 logger.notify("Use the --no-site-packages option to use distribute in "
294 "the virtualenv.")
295 except ImportError:
296 pass
297
298 search_dirs = file_search_dirs()
299
300 if setup_fn is not None:
301 setup_fn = _find_file(setup_fn, search_dirs)
302
303 if source is not None:
304 source = _find_file(source, search_dirs)
305
306 if is_jython and os._name == 'nt':
307 # Jython's .bat sys.executable can't handle a command line
308 # argument with newlines
309 fd, ez_setup = tempfile.mkstemp('.py')
310 os.write(fd, bootstrap_script)
311 os.close(fd)
312 cmd = [py_executable, ez_setup]
313 else:
314 cmd = [py_executable, '-c', bootstrap_script]
315 if unzip:
316 cmd.append('--always-unzip')
317 env = {}
318 remove_from_env = []
319 if logger.stdout_level_matches(logger.DEBUG):
320 cmd.append('-v')
321
322 old_chdir = os.getcwd()
323 if setup_fn is not None and os.path.exists(setup_fn):
324 logger.info('Using existing %s egg: %s' % (project_name, setup_fn))
325 cmd.append(setup_fn)
326 if os.environ.get('PYTHONPATH'):
327 env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH']
328 else:
329 env['PYTHONPATH'] = setup_fn
330 else:
331 # the source is found, let's chdir
332 if source is not None and os.path.exists(source):
333 os.chdir(os.path.dirname(source))
334 # in this case, we want to be sure that PYTHONPATH is unset (not
335 # just empty, really unset), else CPython tries to import the
336 # site.py that it's in virtualenv_support
337 remove_from_env.append('PYTHONPATH')
338 else:
339 logger.info('No %s egg found; downloading' % project_name)
340 cmd.extend(['--always-copy', '-U', project_name])
341 logger.start_progress('Installing %s...' % project_name)
342 logger.indent += 2
343 cwd = None
344 if project_name == 'distribute':
345 env['DONT_PATCH_SETUPTOOLS'] = 'true'
346
347 def _filter_ez_setup(line):
348 return filter_ez_setup(line, project_name)
349
350 if not os.access(os.getcwd(), os.W_OK):
351 cwd = tempfile.mkdtemp()
352 if source is not None and os.path.exists(source):
353 # the current working dir is hostile, let's copy the
354 # tarball to a temp dir
355 target = os.path.join(cwd, os.path.split(source)[-1])
356 shutil.copy(source, target)
357 try:
358 call_subprocess(cmd, show_stdout=False,
359 filter_stdout=_filter_ez_setup,
360 extra_env=env,
361 remove_from_env=remove_from_env,
362 cwd=cwd)
363 finally:
364 logger.indent -= 2
365 logger.end_progress()
366 if os.getcwd() != old_chdir:
367 os.chdir(old_chdir)
368 if is_jython and os._name == 'nt':
369 os.remove(ez_setup)
370
371def file_search_dirs():
372 here = os.path.dirname(os.path.abspath(__file__))
373 dirs = ['.', here,
374 join(here, 'virtualenv_support')]
375 if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
376 # Probably some boot script; just in case virtualenv is installed...
377 try:
378 import virtualenv
379 except ImportError:
380 pass
381 else:
382 dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
383 return [d for d in dirs if os.path.isdir(d)]
384
385def install_setuptools(py_executable, unzip=False):
386 _install_req(py_executable, unzip)
387
388def install_distribute(py_executable, unzip=False):
389 _install_req(py_executable, unzip, distribute=True)
390
391_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I)
392def install_pip(py_executable):
393 filenames = []
394 for dir in file_search_dirs():
395 filenames.extend([join(dir, fn) for fn in os.listdir(dir)
396 if _pip_re.search(fn)])
397 filenames = [(os.path.basename(filename).lower(), i, filename) for i, filename in enumerate(filenames)]
398 filenames.sort()
399 filenames = [filename for basename, i, filename in filenames]
400 if not filenames:
401 filename = 'pip'
402 else:
403 filename = filenames[-1]
404 easy_install_script = 'easy_install'
405 if sys.platform == 'win32':
406 easy_install_script = 'easy_install-script.py'
407 cmd = [py_executable, join(os.path.dirname(py_executable), easy_install_script), filename]
408 if filename == 'pip':
409 logger.info('Installing pip from network...')
410 else:
411 logger.info('Installing %s' % os.path.basename(filename))
412 logger.indent += 2
413 def _filter_setup(line):
414 return filter_ez_setup(line, 'pip')
415 try:
416 call_subprocess(cmd, show_stdout=False,
417 filter_stdout=_filter_setup)
418 finally:
419 logger.indent -= 2
420
421def filter_ez_setup(line, project_name='setuptools'):
422 if not line.strip():
423 return Logger.DEBUG
424 if project_name == 'distribute':
425 for prefix in ('Extracting', 'Now working', 'Installing', 'Before',
426 'Scanning', 'Setuptools', 'Egg', 'Already',
427 'running', 'writing', 'reading', 'installing',
428 'creating', 'copying', 'byte-compiling', 'removing',
429 'Processing'):
430 if line.startswith(prefix):
431 return Logger.DEBUG
432 return Logger.DEBUG
433 for prefix in ['Reading ', 'Best match', 'Processing setuptools',
434 'Copying setuptools', 'Adding setuptools',
435 'Installing ', 'Installed ']:
436 if line.startswith(prefix):
437 return Logger.DEBUG
438 return Logger.INFO
439
440def main():
441 parser = optparse.OptionParser(
442 version=virtualenv_version,
443 usage="%prog [OPTIONS] DEST_DIR")
444
445 parser.add_option(
446 '-v', '--verbose',
447 action='count',
448 dest='verbose',
449 default=0,
450 help="Increase verbosity")
451
452 parser.add_option(
453 '-q', '--quiet',
454 action='count',
455 dest='quiet',
456 default=0,
457 help='Decrease verbosity')
458
459 parser.add_option(
460 '-p', '--python',
461 dest='python',
462 metavar='PYTHON_EXE',
463 help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
464 'interpreter to create the new environment. The default is the interpreter that '
465 'virtualenv was installed with (%s)' % sys.executable)
466
467 parser.add_option(
468 '--clear',
469 dest='clear',
470 action='store_true',
471 help="Clear out the non-root install and start from scratch")
472
473 parser.add_option(
474 '--no-site-packages',
475 dest='no_site_packages',
476 action='store_true',
477 help="Don't give access to the global site-packages dir to the "
478 "virtual environment")
479
480 parser.add_option(
481 '--unzip-setuptools',
482 dest='unzip_setuptools',
483 action='store_true',
484 help="Unzip Setuptools or Distribute when installing it")
485
486 parser.add_option(
487 '--relocatable',
488 dest='relocatable',
489 action='store_true',
490 help='Make an EXISTING virtualenv environment relocatable. '
491 'This fixes up scripts and makes all .pth files relative')
492
493 parser.add_option(
494 '--distribute',
495 dest='use_distribute',
496 action='store_true',
497 help='Use Distribute instead of Setuptools. Set environ variable '
498 'VIRTUALENV_USE_DISTRIBUTE to make it the default ')
499
500 parser.add_option(
501 '--prompt=',
502 dest='prompt',
503 help='Provides an alternative prompt prefix for this environment')
504
505 if 'extend_parser' in globals():
506 extend_parser(parser)
507
508 options, args = parser.parse_args()
509
510 global logger
511
512 if 'adjust_options' in globals():
513 adjust_options(options, args)
514
515 verbosity = options.verbose - options.quiet
516 logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
517
518 if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
519 env = os.environ.copy()
520 interpreter = resolve_interpreter(options.python)
521 if interpreter == sys.executable:
522 logger.warn('Already using interpreter %s' % interpreter)
523 else:
524 logger.notify('Running virtualenv with interpreter %s' % interpreter)
525 env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
526 file = __file__
527 if file.endswith('.pyc'):
528 file = file[:-1]
529 popen = subprocess.Popen([interpreter, file] + sys.argv[1:], env=env)
530 raise SystemExit(popen.wait())
531
532 if not args:
533 print 'You must provide a DEST_DIR'
534 parser.print_help()
535 sys.exit(2)
536 if len(args) > 1:
537 print 'There must be only one argument: DEST_DIR (you gave %s)' % (
538 ' '.join(args))
539 parser.print_help()
540 sys.exit(2)
541
542 home_dir = args[0]
543
544 if os.environ.get('WORKING_ENV'):
545 logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
546 logger.fatal('Please deactivate your workingenv, then re-run this script')
547 sys.exit(3)
548
549 if 'PYTHONHOME' in os.environ:
550 logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it')
551 del os.environ['PYTHONHOME']
552
553 if options.relocatable:
554 make_environment_relocatable(home_dir)
555 return
556
557 create_environment(home_dir, site_packages=not options.no_site_packages, clear=options.clear,
558 unzip_setuptools=options.unzip_setuptools,
559 use_distribute=options.use_distribute,
560 prompt=options.prompt)
561 if 'after_install' in globals():
562 after_install(options, home_dir)
563
564def call_subprocess(cmd, show_stdout=True,
565 filter_stdout=None, cwd=None,
566 raise_on_returncode=True, extra_env=None,
567 remove_from_env=None):
568 cmd_parts = []
569 for part in cmd:
570 if len(part) > 40:
571 part = part[:30]+"..."+part[-5:]
572 if ' ' in part or '\n' in part or '"' in part or "'" in part:
573 part = '"%s"' % part.replace('"', '\\"')
574 cmd_parts.append(part)
575 cmd_desc = ' '.join(cmd_parts)
576 if show_stdout:
577 stdout = None
578 else:
579 stdout = subprocess.PIPE
580 logger.debug("Running command %s" % cmd_desc)
581 if extra_env or remove_from_env:
582 env = os.environ.copy()
583 if extra_env:
584 env.update(extra_env)
585 if remove_from_env:
586 for varname in remove_from_env:
587 env.pop(varname, None)
588 else:
589 env = None
590 try:
591 proc = subprocess.Popen(
592 cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
593 cwd=cwd, env=env)
594 except Exception, e:
595 logger.fatal(
596 "Error %s while executing command %s" % (e, cmd_desc))
597 raise
598 all_output = []
599 if stdout is not None:
600 stdout = proc.stdout
601 while 1:
602 line = stdout.readline()
603 if not line:
604 break
605 line = line.rstrip()
606 all_output.append(line)
607 if filter_stdout:
608 level = filter_stdout(line)
609 if isinstance(level, tuple):
610 level, line = level
611 logger.log(level, line)
612 if not logger.stdout_level_matches(level):
613 logger.show_progress()
614 else:
615 logger.info(line)
616 else:
617 proc.communicate()
618 proc.wait()
619 if proc.returncode:
620 if raise_on_returncode:
621 if all_output:
622 logger.notify('Complete output from command %s:' % cmd_desc)
623 logger.notify('\n'.join(all_output) + '\n----------------------------------------')
624 raise OSError(
625 "Command %s failed with error code %s"
626 % (cmd_desc, proc.returncode))
627 else:
628 logger.warn(
629 "Command %s had error code %s"
630 % (cmd_desc, proc.returncode))
631
632
633def create_environment(home_dir, site_packages=True, clear=False,
634 unzip_setuptools=False, use_distribute=False,
635 prompt=None):
636 """
637 Creates a new environment in ``home_dir``.
638
639 If ``site_packages`` is true (the default) then the global
640 ``site-packages/`` directory will be on the path.
641
642 If ``clear`` is true (default False) then the environment will
643 first be cleared.
644 """
645 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
646
647 py_executable = os.path.abspath(install_python(
648 home_dir, lib_dir, inc_dir, bin_dir,
649 site_packages=site_packages, clear=clear))
650
651 install_distutils(home_dir)
652
653 if use_distribute or os.environ.get('VIRTUALENV_USE_DISTRIBUTE'):
654 install_distribute(py_executable, unzip=unzip_setuptools)
655 else:
656 install_setuptools(py_executable, unzip=unzip_setuptools)
657
658 install_pip(py_executable)
659
660 install_activate(home_dir, bin_dir, prompt)
661
662def path_locations(home_dir):
663 """Return the path locations for the environment (where libraries are,
664 where scripts go, etc)"""
665 # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
666 # prefix arg is broken: http://bugs.python.org/issue3386
667 if sys.platform == 'win32':
668 # Windows has lots of problems with executables with spaces in
669 # the name; this function will remove them (using the ~1
670 # format):
671 mkdir(home_dir)
672 if ' ' in home_dir:
673 try:
674 import win32api
675 except ImportError:
676 print 'Error: the path "%s" has a space in it' % home_dir
677 print 'To handle these kinds of paths, the win32api module must be installed:'
678 print ' http://sourceforge.net/projects/pywin32/'
679 sys.exit(3)
680 home_dir = win32api.GetShortPathName(home_dir)
681 lib_dir = join(home_dir, 'Lib')
682 inc_dir = join(home_dir, 'Include')
683 bin_dir = join(home_dir, 'Scripts')
684 elif is_jython:
685 lib_dir = join(home_dir, 'Lib')
686 inc_dir = join(home_dir, 'Include')
687 bin_dir = join(home_dir, 'bin')
688 elif is_pypy:
689 lib_dir = home_dir
690 inc_dir = join(home_dir, 'include')
691 bin_dir = join(home_dir, 'bin')
692 else:
693 lib_dir = join(home_dir, 'lib', py_version)
694 inc_dir = join(home_dir, 'include', py_version)
695 bin_dir = join(home_dir, 'bin')
696 return home_dir, lib_dir, inc_dir, bin_dir
697
698
699def change_prefix(filename, dst_prefix):
700 prefixes = [sys.prefix]
701 if hasattr(sys, 'real_prefix'):
702 prefixes.append(sys.real_prefix)
703 prefixes = map(os.path.abspath, prefixes)
704 filename = os.path.abspath(filename)
705 for src_prefix in prefixes:
706 if filename.startswith(src_prefix):
707 _, relpath = filename.split(src_prefix, 1)
708 assert relpath[0] == os.sep
709 relpath = relpath[1:]
710 return join(dst_prefix, relpath)
711 assert False, "Filename %s does not start with any of these prefixes: %s" % \
712 (filename, prefixes)
713
714def copy_required_modules(dst_prefix):
715 import imp
716 for modname in REQUIRED_MODULES:
717 if modname in sys.builtin_module_names:
718 logger.info("Ignoring built-in bootstrap module: %s" % modname)
719 continue
720 try:
721 f, filename, _ = imp.find_module(modname)
722 except ImportError:
723 logger.info("Cannot import bootstrap module: %s" % modname)
724 else:
725 if f is not None:
726 f.close()
727 dst_filename = change_prefix(filename, dst_prefix)
728 copyfile(filename, dst_filename)
729 if filename.endswith('.pyc'):
730 pyfile = filename[:-1]
731 if os.path.exists(pyfile):
732 copyfile(pyfile, dst_filename[:-1])
733
734
735def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
736 """Install just the base environment, no distutils patches etc"""
737 if sys.executable.startswith(bin_dir):
738 print 'Please use the *system* python to run this script'
739 return
740
741 if clear:
742 rmtree(lib_dir)
743 ## FIXME: why not delete it?
744 ## Maybe it should delete everything with #!/path/to/venv/python in it
745 logger.notify('Not deleting %s', bin_dir)
746
747 if hasattr(sys, 'real_prefix'):
748 logger.notify('Using real prefix %r' % sys.real_prefix)
749 prefix = sys.real_prefix
750 else:
751 prefix = sys.prefix
752 mkdir(lib_dir)
753 fix_lib64(lib_dir)
754 stdlib_dirs = [os.path.dirname(os.__file__)]
755 if sys.platform == 'win32':
756 stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
757 elif sys.platform == 'darwin':
758 stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
759 if hasattr(os, 'symlink'):
760 logger.info('Symlinking Python bootstrap modules')
761 else:
762 logger.info('Copying Python bootstrap modules')
763 logger.indent += 2
764 try:
765 # copy required files...
766 for stdlib_dir in stdlib_dirs:
767 if not os.path.isdir(stdlib_dir):
768 continue
769 for fn in os.listdir(stdlib_dir):
770 if fn != 'site-packages' and os.path.splitext(fn)[0] in REQUIRED_FILES:
771 copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
772 # ...and modules
773 copy_required_modules(home_dir)
774 finally:
775 logger.indent -= 2
776 mkdir(join(lib_dir, 'site-packages'))
777 import site
778 site_filename = site.__file__
779 if site_filename.endswith('.pyc'):
780 site_filename = site_filename[:-1]
781 elif site_filename.endswith('$py.class'):
782 site_filename = site_filename.replace('$py.class', '.py')
783 site_filename_dst = change_prefix(site_filename, home_dir)
784 site_dir = os.path.dirname(site_filename_dst)
785 writefile(site_filename_dst, SITE_PY)
786 writefile(join(site_dir, 'orig-prefix.txt'), prefix)
787 site_packages_filename = join(site_dir, 'no-global-site-packages.txt')
788 if not site_packages:
789 writefile(site_packages_filename, '')
790 else:
791 if os.path.exists(site_packages_filename):
792 logger.info('Deleting %s' % site_packages_filename)
793 os.unlink(site_packages_filename)
794
795 if is_pypy:
796 stdinc_dir = join(prefix, 'include')
797 else:
798 stdinc_dir = join(prefix, 'include', py_version)
799 if os.path.exists(stdinc_dir):
800 copyfile(stdinc_dir, inc_dir)
801 else:
802 logger.debug('No include dir %s' % stdinc_dir)
803
804 if sys.exec_prefix != prefix:
805 if sys.platform == 'win32':
806 exec_dir = join(sys.exec_prefix, 'lib')
807 elif is_jython:
808 exec_dir = join(sys.exec_prefix, 'Lib')
809 else:
810 exec_dir = join(sys.exec_prefix, 'lib', py_version)
811 for fn in os.listdir(exec_dir):
812 copyfile(join(exec_dir, fn), join(lib_dir, fn))
813
814 if is_jython:
815 # Jython has either jython-dev.jar and javalib/ dir, or just
816 # jython.jar
817 for name in 'jython-dev.jar', 'javalib', 'jython.jar':
818 src = join(prefix, name)
819 if os.path.exists(src):
820 copyfile(src, join(home_dir, name))
821 # XXX: registry should always exist after Jython 2.5rc1
822 src = join(prefix, 'registry')
823 if os.path.exists(src):
824 copyfile(src, join(home_dir, 'registry'), symlink=False)
825 copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
826 symlink=False)
827
828 mkdir(bin_dir)
829 py_executable = join(bin_dir, os.path.basename(sys.executable))
830 if 'Python.framework' in prefix:
831 if re.search(r'/Python(?:-32|-64)*$', py_executable):
832 # The name of the python executable is not quite what
833 # we want, rename it.
834 py_executable = os.path.join(
835 os.path.dirname(py_executable), 'python')
836
837 logger.notify('New %s executable in %s', expected_exe, py_executable)
838 if sys.executable != py_executable:
839 ## FIXME: could I just hard link?
840 executable = sys.executable
841 if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'):
842 # Cygwin misreports sys.executable sometimes
843 executable += '.exe'
844 py_executable += '.exe'
845 logger.info('Executable actually exists in %s' % executable)
846 shutil.copyfile(executable, py_executable)
847 make_exe(py_executable)
848 if sys.platform == 'win32' or sys.platform == 'cygwin':
849 pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
850 if os.path.exists(pythonw):
851 logger.info('Also created pythonw.exe')
852 shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
853 if is_pypy:
854 # make a symlink python --> pypy-c
855 python_executable = os.path.join(os.path.dirname(py_executable), 'python')
856 logger.info('Also created executable %s' % python_executable)
857 copyfile(py_executable, python_executable)
858
859 if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
860 secondary_exe = os.path.join(os.path.dirname(py_executable),
861 expected_exe)
862 py_executable_ext = os.path.splitext(py_executable)[1]
863 if py_executable_ext == '.exe':
864 # python2.4 gives an extension of '.4' :P
865 secondary_exe += py_executable_ext
866 if os.path.exists(secondary_exe):
867 logger.warn('Not overwriting existing %s script %s (you must use %s)'
868 % (expected_exe, secondary_exe, py_executable))
869 else:
870 logger.notify('Also creating executable in %s' % secondary_exe)
871 shutil.copyfile(sys.executable, secondary_exe)
872 make_exe(secondary_exe)
873
874 if 'Python.framework' in prefix:
875 logger.debug('MacOSX Python framework detected')
876
877 # Make sure we use the the embedded interpreter inside
878 # the framework, even if sys.executable points to
879 # the stub executable in ${sys.prefix}/bin
880 # See http://groups.google.com/group/python-virtualenv/
881 # browse_thread/thread/17cab2f85da75951
882 original_python = os.path.join(
883 prefix, 'Resources/Python.app/Contents/MacOS/Python')
884 shutil.copy(original_python, py_executable)
885
886 # Copy the framework's dylib into the virtual
887 # environment
888 virtual_lib = os.path.join(home_dir, '.Python')
889
890 if os.path.exists(virtual_lib):
891 os.unlink(virtual_lib)
892 copyfile(
893 os.path.join(prefix, 'Python'),
894 virtual_lib)
895
896 # And then change the install_name of the copied python executable
897 try:
898 call_subprocess(
899 ["install_name_tool", "-change",
900 os.path.join(prefix, 'Python'),
901 '@executable_path/../.Python',
902 py_executable])
903 except:
904 logger.fatal(
905 "Could not call install_name_tool -- you must have Apple's development tools installed")
906 raise
907
908 # Some tools depend on pythonX.Y being present
909 py_executable_version = '%s.%s' % (
910 sys.version_info[0], sys.version_info[1])
911 if not py_executable.endswith(py_executable_version):
912 # symlinking pythonX.Y > python
913 pth = py_executable + '%s.%s' % (
914 sys.version_info[0], sys.version_info[1])
915 if os.path.exists(pth):
916 os.unlink(pth)
917 os.symlink('python', pth)
918 else:
919 # reverse symlinking python -> pythonX.Y (with --python)
920 pth = join(bin_dir, 'python')
921 if os.path.exists(pth):
922 os.unlink(pth)
923 os.symlink(os.path.basename(py_executable), pth)
924
925 if sys.platform == 'win32' and ' ' in py_executable:
926 # There's a bug with subprocess on Windows when using a first
927 # argument that has a space in it. Instead we have to quote
928 # the value:
929 py_executable = '"%s"' % py_executable
930 cmd = [py_executable, '-c', 'import sys; print sys.prefix']
931 logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
932 proc = subprocess.Popen(cmd,
933 stdout=subprocess.PIPE)
934 proc_stdout, proc_stderr = proc.communicate()
935 proc_stdout = os.path.normcase(os.path.abspath(proc_stdout.strip()))
936 if proc_stdout != os.path.normcase(os.path.abspath(home_dir)):
937 logger.fatal(
938 'ERROR: The executable %s is not functioning' % py_executable)
939 logger.fatal(
940 'ERROR: It thinks sys.prefix is %r (should be %r)'
941 % (proc_stdout, os.path.normcase(os.path.abspath(home_dir))))
942 logger.fatal(
943 'ERROR: virtualenv is not compatible with this system or executable')
944 if sys.platform == 'win32':
945 logger.fatal(
946 'Note: some Windows users have reported this error when they installed Python for "Only this user". The problem may be resolvable if you install Python "For all users". (See https://bugs.launchpad.net/virtualenv/+bug/352844)')
947 sys.exit(100)
948 else:
949 logger.info('Got sys.prefix result: %r' % proc_stdout)
950
951 pydistutils = os.path.expanduser('~/.pydistutils.cfg')
952 if os.path.exists(pydistutils):
953 logger.notify('Please make sure you remove any previous custom paths from '
954 'your %s file.' % pydistutils)
955 ## FIXME: really this should be calculated earlier
956 return py_executable
957
958def install_activate(home_dir, bin_dir, prompt=None):
959 if sys.platform == 'win32' or is_jython and os._name == 'nt':
960 files = {'activate.bat': ACTIVATE_BAT,
961 'deactivate.bat': DEACTIVATE_BAT}
962 if os.environ.get('OS') == 'Windows_NT' and os.environ.get('OSTYPE') == 'cygwin':
963 files['activate'] = ACTIVATE_SH
964 else:
965 files = {'activate': ACTIVATE_SH}
966
967 # suppling activate.fish in addition to, not instead of, the
968 # bash script support.
969 files['activate.fish'] = ACTIVATE_FISH
970
971 # same for csh/tcsh support...
972 files['activate.csh'] = ACTIVATE_CSH
973
974
975
976 files['activate_this.py'] = ACTIVATE_THIS
977 vname = os.path.basename(os.path.abspath(home_dir))
978 for name, content in files.items():
979 content = content.replace('__VIRTUAL_PROMPT__', prompt or '')
980 content = content.replace('__VIRTUAL_WINPROMPT__', prompt or '(%s)' % vname)
981 content = content.replace('__VIRTUAL_ENV__', os.path.abspath(home_dir))
982 content = content.replace('__VIRTUAL_NAME__', vname)
983 content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
984 writefile(os.path.join(bin_dir, name), content)
985
986def install_distutils(home_dir):
987 distutils_path = change_prefix(distutils.__path__[0], home_dir)
988 mkdir(distutils_path)
989 ## FIXME: maybe this prefix setting should only be put in place if
990 ## there's a local distutils.cfg with a prefix setting?
991 home_dir = os.path.abspath(home_dir)
992 ## FIXME: this is breaking things, removing for now:
993 #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
994 writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
995 writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
996
997def fix_lib64(lib_dir):
998 """
999 Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
1000 instead of lib/pythonX.Y. If this is such a platform we'll just create a
1001 symlink so lib64 points to lib
1002 """
1003 if [p for p in distutils.sysconfig.get_config_vars().values()
1004 if isinstance(p, basestring) and 'lib64' in p]:
1005 logger.debug('This system uses lib64; symlinking lib64 to lib')
1006 assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
1007 "Unexpected python lib dir: %r" % lib_dir)
1008 lib_parent = os.path.dirname(lib_dir)
1009 assert os.path.basename(lib_parent) == 'lib', (
1010 "Unexpected parent dir: %r" % lib_parent)
1011 copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64'))
1012
1013def resolve_interpreter(exe):
1014 """
1015 If the executable given isn't an absolute path, search $PATH for the interpreter
1016 """
1017 if os.path.abspath(exe) != exe:
1018 paths = os.environ.get('PATH', '').split(os.pathsep)
1019 for path in paths:
1020 if os.path.exists(os.path.join(path, exe)):
1021 exe = os.path.join(path, exe)
1022 break
1023 if not os.path.exists(exe):
1024 logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
1025 sys.exit(3)
1026 return exe
1027
1028############################################################
1029## Relocating the environment:
1030
1031def make_environment_relocatable(home_dir):
1032 """
1033 Makes the already-existing environment use relative paths, and takes out
1034 the #!-based environment selection in scripts.
1035 """
1036 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
1037 activate_this = os.path.join(bin_dir, 'activate_this.py')
1038 if not os.path.exists(activate_this):
1039 logger.fatal(
1040 'The environment doesn\'t have a file %s -- please re-run virtualenv '
1041 'on this environment to update it' % activate_this)
1042 fixup_scripts(home_dir)
1043 fixup_pth_and_egg_link(home_dir)
1044 ## FIXME: need to fix up distutils.cfg
1045
1046OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
1047 'activate', 'activate.bat', 'activate_this.py']
1048
1049def fixup_scripts(home_dir):
1050 # This is what we expect at the top of scripts:
1051 shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
1052 # This is what we'll put:
1053 new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
1054 activate = "import os; activate_this=os.path.join(os.path.dirname(__file__), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this"
1055 if sys.platform == 'win32':
1056 bin_suffix = 'Scripts'
1057 else:
1058 bin_suffix = 'bin'
1059 bin_dir = os.path.join(home_dir, bin_suffix)
1060 home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
1061 for filename in os.listdir(bin_dir):
1062 filename = os.path.join(bin_dir, filename)
1063 if not os.path.isfile(filename):
1064 # ignore subdirs, e.g. .svn ones.
1065 continue
1066 f = open(filename, 'rb')
1067 lines = f.readlines()
1068 f.close()
1069 if not lines:
1070 logger.warn('Script %s is an empty file' % filename)
1071 continue
1072 if not lines[0].strip().startswith(shebang):
1073 if os.path.basename(filename) in OK_ABS_SCRIPTS:
1074 logger.debug('Cannot make script %s relative' % filename)
1075 elif lines[0].strip() == new_shebang:
1076 logger.info('Script %s has already been made relative' % filename)
1077 else:
1078 logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
1079 % (filename, shebang))
1080 continue
1081 logger.notify('Making script %s relative' % filename)
1082 lines = [new_shebang+'\n', activate+'\n'] + lines[1:]
1083 f = open(filename, 'wb')
1084 f.writelines(lines)
1085 f.close()
1086
1087def fixup_pth_and_egg_link(home_dir, sys_path=None):
1088 """Makes .pth and .egg-link files use relative paths"""
1089 home_dir = os.path.normcase(os.path.abspath(home_dir))
1090 if sys_path is None:
1091 sys_path = sys.path
1092 for path in sys_path:
1093 if not path:
1094 path = '.'
1095 if not os.path.isdir(path):
1096 continue
1097 path = os.path.normcase(os.path.abspath(path))
1098 if not path.startswith(home_dir):
1099 logger.debug('Skipping system (non-environment) directory %s' % path)
1100 continue
1101 for filename in os.listdir(path):
1102 filename = os.path.join(path, filename)
1103 if filename.endswith('.pth'):
1104 if not os.access(filename, os.W_OK):
1105 logger.warn('Cannot write .pth file %s, skipping' % filename)
1106 else:
1107 fixup_pth_file(filename)
1108 if filename.endswith('.egg-link'):
1109 if not os.access(filename, os.W_OK):
1110 logger.warn('Cannot write .egg-link file %s, skipping' % filename)
1111 else:
1112 fixup_egg_link(filename)
1113
1114def fixup_pth_file(filename):
1115 lines = []
1116 prev_lines = []
1117 f = open(filename)
1118 prev_lines = f.readlines()
1119 f.close()
1120 for line in prev_lines:
1121 line = line.strip()
1122 if (not line or line.startswith('#') or line.startswith('import ')
1123 or os.path.abspath(line) != line):
1124 lines.append(line)
1125 else:
1126 new_value = make_relative_path(filename, line)
1127 if line != new_value:
1128 logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
1129 lines.append(new_value)
1130 if lines == prev_lines:
1131 logger.info('No changes to .pth file %s' % filename)
1132 return
1133 logger.notify('Making paths in .pth file %s relative' % filename)
1134 f = open(filename, 'w')
1135 f.write('\n'.join(lines) + '\n')
1136 f.close()
1137
1138def fixup_egg_link(filename):
1139 f = open(filename)
1140 link = f.read().strip()
1141 f.close()
1142 if os.path.abspath(link) != link:
1143 logger.debug('Link in %s already relative' % filename)
1144 return
1145 new_link = make_relative_path(filename, link)
1146 logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
1147 f = open(filename, 'w')
1148 f.write(new_link)
1149 f.close()
1150
1151def make_relative_path(source, dest, dest_is_directory=True):
1152 """
1153 Make a filename relative, where the filename is dest, and it is
1154 being referred to from the filename source.
1155
1156 >>> make_relative_path('/usr/share/something/a-file.pth',
1157 ... '/usr/share/another-place/src/Directory')
1158 '../another-place/src/Directory'
1159 >>> make_relative_path('/usr/share/something/a-file.pth',
1160 ... '/home/user/src/Directory')
1161 '../../../home/user/src/Directory'
1162 >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
1163 './'
1164 """
1165 source = os.path.dirname(source)
1166 if not dest_is_directory:
1167 dest_filename = os.path.basename(dest)
1168 dest = os.path.dirname(dest)
1169 dest = os.path.normpath(os.path.abspath(dest))
1170 source = os.path.normpath(os.path.abspath(source))
1171 dest_parts = dest.strip(os.path.sep).split(os.path.sep)
1172 source_parts = source.strip(os.path.sep).split(os.path.sep)
1173 while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
1174 dest_parts.pop(0)
1175 source_parts.pop(0)
1176 full_parts = ['..']*len(source_parts) + dest_parts
1177 if not dest_is_directory:
1178 full_parts.append(dest_filename)
1179 if not full_parts:
1180 # Special case for the current directory (otherwise it'd be '')
1181 return './'
1182 return os.path.sep.join(full_parts)
1183
1184
1185
1186############################################################
1187## Bootstrap script creation:
1188
1189def create_bootstrap_script(extra_text, python_version=''):
1190 """
1191 Creates a bootstrap script, which is like this script but with
1192 extend_parser, adjust_options, and after_install hooks.
1193
1194 This returns a string that (written to disk of course) can be used
1195 as a bootstrap script with your own customizations. The script
1196 will be the standard virtualenv.py script, with your extra text
1197 added (your extra text should be Python code).
1198
1199 If you include these functions, they will be called:
1200
1201 ``extend_parser(optparse_parser)``:
1202 You can add or remove options from the parser here.
1203
1204 ``adjust_options(options, args)``:
1205 You can change options here, or change the args (if you accept
1206 different kinds of arguments, be sure you modify ``args`` so it is
1207 only ``[DEST_DIR]``).
1208
1209 ``after_install(options, home_dir)``:
1210
1211 After everything is installed, this function is called. This
1212 is probably the function you are most likely to use. An
1213 example would be::
1214
1215 def after_install(options, home_dir):
1216 subprocess.call([join(home_dir, 'bin', 'easy_install'),
1217 'MyPackage'])
1218 subprocess.call([join(home_dir, 'bin', 'my-package-script'),
1219 'setup', home_dir])
1220
1221 This example immediately installs a package, and runs a setup
1222 script from that package.
1223
1224 If you provide something like ``python_version='2.4'`` then the
1225 script will start with ``#!/usr/bin/env python2.4`` instead of
1226 ``#!/usr/bin/env python``. You can use this when the script must
1227 be run with a particular Python version.
1228 """
1229 filename = __file__
1230 if filename.endswith('.pyc'):
1231 filename = filename[:-1]
1232 f = open(filename, 'rb')
1233 content = f.read()
1234 f.close()
1235 py_exe = 'python%s' % python_version
1236 content = (('#!/usr/bin/env %s\n' % py_exe)
1237 + '## WARNING: This file is generated\n'
1238 + content)
1239 return content.replace('##EXT' 'END##', extra_text)
1240
1241#
1242# Copyright 2010 Leonard Thomas
1243#
1244# This file is part of Dodai.
1245#
1246# Dodai is free software: you can redistribute it and/or modify
1247# it under the terms of the GNU General Public License as published by
1248# the Free Software Foundation, either version 3 of the License, or
1249# (at your option) any later version.
1250#
1251# Dodai is distributed in the hope that it will be useful,
1252# but WITHOUT ANY WARRANTY; without even the implied warranty of
1253# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1254# GNU General Public License for more details.
1255#
1256# You should have received a copy of the GNU General Public License
1257# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
1258
1259
1260
1261import os
1262from collections import namedtuple
1263from subprocess import Popen
1264from subprocess import call
1265from subprocess import PIPE
1266
1267def build_paths(home_dir):
1268
1269 obj = namedtuple('Paths', 'wd, home, bin, src, python')
1270
1271 wd = os.getcwd()
1272 if home_dir.startswith(os.sep):
1273 home = home_dir
1274 else:
1275 home = os.path.realpath(os.path.join(wd, home_dir))
1276 bin = os.path.join(home, 'bin')
1277 src = os.path.join(home, 'src')
1278 python = os.path.join(bin, 'python')
1279
1280 return obj(wd, home, bin, src, python)
1281
1282
1283class EasyInstall(object):
1284
1285 def __init__(self, paths):
1286 self._easy_install = os.path.join(paths.bin, 'easy_install')
1287
1288 def __call__(self, package):
1289 cmd = [self._easy_install, '-Uv', package]
1290 call(cmd)
1291
1292
1293class HgClone(object):
1294
1295 def __init__(self, paths, easy_install=EasyInstall):
1296 self._easy_install = easy_install(paths)
1297 self._paths = paths
1298 self._hg_ = None
1299
1300 @property
1301 def _hg(self):
1302 if not self._hg_:
1303 cmd = ['which', 'hg']
1304 self._hg_ = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()[0]\
1305 .strip()
1306 if not self._hg_:
1307 self._hg_ = os.path.join(self._paths.bin, 'hg')
1308 if not os.path.exists(self._hg_):
1309 self._easy_install('mercurial')
1310 self._hg_ = os.path.join(self._paths.bin, 'hg')
1311 return self._hg_
1312
1313 def __call__(self, url, dest):
1314 if not dest.startswith(os.sep):
1315 dest = os.path.join(self._paths.home, dest)
1316 cmd = [self._hg, 'clone', url, dest]
1317 call(cmd)
1318
1319
1320class SetupPy(object):
1321
1322 FILE = 'setup.py'
1323
1324 def __init__(self, paths):
1325 self._paths = paths
1326
1327 def __call__(self, dir, command):
1328 path = os.path.join(self._paths.home, dir)
1329 name = os.path.join(path, self.FILE)
1330 if os.path.exists(name):
1331 os.chdir(path)
1332 cmd = [self._paths.python, name, command]
1333 call(cmd)
1334
1335class RunPythonProgram(object):
1336
1337 def __init__(self, paths):
1338 self._paths = paths
1339
1340 def __call__(self, program):
1341 path = os.path.join(self._paths.bin, program)
1342 if os.path.exists(path):
1343 cmd = [self._paths.python, path]
1344 call(cmd)
1345
1346
1347def after_install(options, home_dir):
1348 paths = build_paths(home_dir)
1349 easy_install = EasyInstall(paths)
1350 hg_clone = HgClone(paths)
1351 setup_py = SetupPy(paths)
1352 run_program = RunPythonProgram(paths)
1353 for package in ['nose', 'virtualenv', 'ipython', 'pylint']:
1354 easy_install(package)
1355 hg_clone('https://dodai.googlecode.com/hg/', 'src')
1356 for dir in ['src']:
1357 setup_py(dir, 'develop')
1358 for program in []:
1359 run_program(program)
1360
1361##file site.py
1362SITE_PY = """
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
1496""".decode("base64").decode("zlib")
1497
1498##file ez_setup.py
1499EZ_SETUP_PY = """
1500eJzNWmuP28YV/a5fwShYSIJlLt8PGXKRJi5gIEiDPAoU9lY7zxVrilRJyhu1yH/vmeFDJLVU2iIf
1501ysDZXXJ45z7PuXekL784nqt9ns3m8/kf87wqq4IcjVJUp2OV52lpJFlZkTQlVYJFs/fSOOcn45lk
1502lVHlxqkUw7XqaWEcCftEnsSirB+ax/Pa+PuprLCApScujGqflDOZpEK9Uu0hhByEwZNCsCovzsZz
1503Uu2NpFobJOMG4Vy/oDZUa6v8aOSy3qmVv9nMZgYuWeQHQ/xzp+8byeGYF5XScnfRUq8b3lquriwr
1504xD9OUMcgRnkULJEJMz6LooQT1N6XV9fqd6zi+XOW5oTPDklR5MXayAvtHZIZJK1EkZFKdIsulq71
1505pgyreG6UuUHPRnk6HtNzkj3NlLHkeCzyY5Go1/OjCoL2w+Pj2ILHR3M2+0m5SfuV6Y2VRGEUJ/xe
1506KlNYkRy1eU1UtZbHp4LwfhxNlQyzxnnluZx98+5PX/387U+7v7z74cf3f/7O2BpzywyYbc+7Rz//
15078K3yq3q0r6rj5v7+eD4mZp1cZl483TdJUd7flff4r9vtfm7cqV3Mxr8fNu7DbHbg/o6TikDgv3TE
1508Fpc3XmNzar8+nh3TNcXT02JjLKLIcRiRsWU7vsUjL6JxHNBQOj4LRMDIYn1DitdKoWFMIuJZrvB8
1509y5GURr4QrrRjzw5dn9EJKc5QFz/ww9CPeUQCHknmeVZokZhboRM6PI5vS+l08WAAibgdxNyhIghs
1510SVyHBMJ3hCcjZ8oid6gLpa7NLMlCN45J4PphHIc+IzyWPrECO7oppdPFjUjEcJcHgnHHcbxQ2mEs
1511Q06CIJaETUjxhroEjuX5xPEE94QtKAtDKSw3JsQTgQyFf1PKxS+MOsSOfOgRccKkpA63oY/lUpfa
1512zHtZChvlC3WlQ33fjXmAuIYy9AgPY9uBIBJb0YRFbJwvsIcLDk8GIXe4I6WwPcuK3cCTDvEmIs1s
1513a6gMgzscQn3uEsvxA88PEB9mu5FlkdCKrdtiOm38kONFxCimkRWGDvNj4rsk8lyX+JxPeqYW47di
1514uPACwiL4Mg5ZFPt+6AhfRD7SUdCIhbfFBJ02kUAlESGtAA5ymAg824M0B0bC4RPRBqgMfeNQIghq
15152HY53kcZOZEIKfGpT6ARF7fFXCLFAzeWMbUgzGOe48Wh5XpcMEcwizmTkbKHvgk8FnvSpTIkIbLQ
1516FSxyhUUdhDv0YurcFtP5hkoSO7ZlUY4wcdQEJAnOXQQ+8KwomBAzwhlpWYFHZUCIQ0NuQS141kNi
1517W5EdMmcqUCOcCezAjh0hmOtLLxSImh0wHhDbgVQnnJIywhlpRwAogC+XSBXi+DGLIUXaPKRhJCfQ
1518io1wRliCh14QOSyOIyppCE9HFrLXQsxDeyrY7jBIhAppB5JzGOb7vu1Fns1C4BePozjwp6SM0Ipa
1519NLZdmzBCXceCM4BzofQ85gMoQlvelNJZhCSR2DPgnqTSRUVRGXsBs+AqoJ6YShhvaFGk0BrA7zqM
152005iFDmXSA3w5gXQiIqfQyh9aJEQseWRBHRQkMla6ApjuhwAMHtnBVKT9oUVEAqu4BKvYoWULAeeG
1521ICefMhAeCaZQxh/FKOKuDAAIHmOERKHtIXG4G1LGuMt9PiElGFqEgonA8pFtB2CiKPJCByLAmL4X
1522o7SngDMYsRvzAyL9kMK/6B5QDYEFQzzPRYH5ZAobgqFF1JERCX0HZA/YpS5I2kKoufAlWgnfnZAS
1523juDOQoxkTDhzSWD7wrdtH2WIliICBE7mSzhiAhLJ2PfAAhxYbkkahEza0kEY8MiZqoBwaJEHjiXA
1524W4mWAQXouZ5t25KLyLXxL5zSJRp1Q5bqhZwYHok5+EOlIAA8ci3VWFm3pXQWMUrcCNiAnsOLXGap
1525nEW2wdkMzDJJA9HQIjt07BAgh0DHnNm+5ccW8SPqCtR57E9FOh5aBN2ZZ6GZsZWHqRcHwmOSCiuC
1526rcyainQ8QgYkGRo7cKsbRTwAOhEhrADgxQLXm+rvGimdRVIgtK7wiR1S22EIE/M9m4bgXjC/mGKS
1527eMhHjKBsbKlQkziCA5js2AWzhdSPHfQ4kPLrrDcRYLwpZ1Vx3tQD156U+zSh7byF3n0mfmECo8Z7
1528feedGomatXjYXzfjQhq7zyRN0O2LHW4todMuwzy4NtQAsNpoAxJptPfVzNiOB/VDdfEEs0WFcUGJ
15290C+ae/FLfRfzXbsMcpqVX2w7KR9a0Q8XeerC3IVp8O1bNZ2UFRcF5rrlYIW65sqkxoJmPrzDFEYw
1530hvEvDGP5fV6WCU174x9GOvx9+MNqfiXsrjNz8Gg1+EvpI35JqqVT3y8Q3CLT7qodOhoO9aJmvNqO
1531hrl1p9aOklJsewPdGpPiDqPqNi9NdirwW51M3QtcpOS8tf1ZEySMjV+dqvwAPzBMl2eMohm/78zu
1532nRSouf5APiGWGJ4/w1VEOQjOU6YdSbWvx/nHRulHo9znp5SraZbUvu5Layfz7HSgojCqPakMDMKd
1533YC1LTcCZ8q4hMfV2Sp0yrl8RxuPAEY+GGmmXz/uE7dvdBbRWRxO1PGNxv1iZULL20qPaUsnpHWPs
1534RTE4IHlOMHPTSyYIvkZG1gmuVc5y+CMtBOHni/rY473sqafdrrdrzia0mKrRUkujQqvSOESfWLA8
153542Xtm1aNI0GiKKfCI6qskipB6LKn3nlGHfHG/jwT+jyhPhvhtV5wap4qH754PqK0bA4bRCNMn+UU
1536+Qk7iVqVus6IcRBlSZ5EfcBxKbrHR50vBUlKYfx4LitxePeL8ldWByIzSIV79ckGoQpalPEqBZUx
15379amH2Wao/vlMyl2NQrB/ayyOn552hSjzU8FEuVAIo7Y/5PyUilKdkvQAdPy4rglUHUceNG5bri5I
1538olJueymaXl02HhuVYFt261GhXTCgLRITnhVFtbTWapMeyDVA3e30pn+6Q9tjvl0TmJ0G5q2SUQcI
1539wD6WNXCQfvgCwncvtYDUd0jz6HqHgWizSa7l/KLx2+38VeOq1ZtGdl+FoYC/1Cu/zjOZJqyCazZ9
15409O9H/r9F+/lP+0v2T+T78u32rlx1tdzWsD7K/JgNAX/OSLaoVEl1JQLMUMd3ukaa4zpVLacsQyqb
1541xvepQIa0y6/kqRpSpQwAErCl1VAmRQlHnEpVDgtIOLehN17/3FN+YY7kfcw+ZsuvT0UBaYDzWsBd
1542MeKtFVjrksvCJMVT+cF6uM1ZOn5pKYYxQKIPw7nuV9qHUZ0+qFe+hLUayfNPA1Ev5eB01nyToCQS
1543elIM/l1e/SkHL9zO55ppXyrr35tuVfGjPAc8+80LpKrLmFxIwUhzVrckGj5rG5KqPiHWLcb/KcnW
1544EK0+A2hJ9rc4Vt1Tu14TbI37jxfOnODFvGbDlgwVqbDqRNKLEQ3JDImk/YihANdQB9m6RwqldZ61
1545/erW6IHZ67sSvfddqVrveb9wRkfgda5Cbp87lM+MV8MWsSSfBbTfoiWvSeHveZItWwppl9biyoIp
1546cbpP/g5s3rbWCqra11GkZVUua7GrjSqwrz7niUqgoyCKL1t1yq4+BniuLp2KHIKUN8rWS2n+NFil
1547mnEVl+G76sJK85kU2VL5+fXvd9WfkDTA2iB5+VKW3+mUUJ+cLMVnkak/YM4Rys72Ij2qvu99nW29
15483qNLFTQnKv/VZztL5YoZKGFtAF1m6tYB5ZwJOBKvoA5V5wuEFs8KjwnG2bLUb/c5QCO4OWu2BHQ3
1549Pc5lR6jM22w2Z7MlQExslIe1mANhe9Vu8VzUxLRHeKFE9ZwXn5pN18axZpecVqT5XE4hhUaJu3I2
1550UygCDzDdtesFkHypxKZyCtGwVd8Ac/V7RhFJsb5KmR7oXjVUOsvWqpquXkNHoZO1StRk2TROqRDH
1551N/WP5aj3GmZnC8OaF8u53mLEe7rkGnww8TM/imx5texL4wc0/ffPRVIBfBBj+Fe328DwT2v10eCz
1552ip5qF1ihyhDQyPKiOOnkSMVImI57Pz1UF14Jvb7FxPZqPmabGsJhgKkGkuVqqHGNItqaGivW82c6
1553hzvxwNR21GN49xKGQTUUbsYQgA02eheW5qVYrq4goqw2Wmj/ecNmLWhBwVT90sLW7D+5FH8fkOlL
1554NCyf11OMfeHc97c+NNUc+w6tVbOqJYiXmunRh9G3Oul6eOiw+kriZc3tAUNP6tZ1SzYcIwZThI6Z
1555Ko3e7MDywwGGmoMesj3OIc1A1l5NjLSLU3CB9vPqlTpteVjpNH0Wi0KntTAUjf9mqihLlZ9HXKXU
1556vuYQLDplmAA/LTuzhg1n0m/czd2u8dZuZ2wxElqmZdqL/3pE+CsAXoOrmotpmacCtToxGrdNP8ik
1557buyvGvpCHPLPGm91JOrvPOgJGMxRAXrT38DdUac+2ZI3RfWPYbPSm7z63c71MPgfDHT4eaP/Hk1t
1558m+ls/59T8laZdYJ/U8pVNr9Ud225PQxndu1sa4XEh1WK/RE4pjNFPXk5Q9Uuv5MDOvW15jemsDrN
15595z9etUXzdYsoc4DgkyaiQh3/IgnRJF0Sev6CvMXyB7RT8/bbOebxPJw+5/X3bq6/mmKuFs2x5rHj
1560p3aEKS/w/LN+aqgSoackrV7X58QQ+aSGu7NC5H4WF838o3qt9ly5E3txiO65L921+lOtWF66ai2k
15615UJNmouCLi7PumNm9e5Dc0QtW1J98ZhadmRXj4A1RX+Yqz/uig3+rYEVGB+aTrNuyNqNTJDvoVyu
1562HrqXzRIWd9R5VEPFfF5PCjVJ9x2DCGCErNqJQX+faNveNZ9EVRetur/sT+c73THsdk3Wdy5pZKwN
15637ZY3TUvUOuDN2NgDqTANbqGnWQpSsP1y/jHrfx/oY7b88LdfH16tfp3r9mTVH2P02z0segGxQeT6
1564G1mpIRQKfDG/LtIWEWtV8f8PGy3Y1K330l49YAzTjnyln9YPMbri0ebhZfMXz01OyKY96lTvOWAG
1565M1o/breL3U4V7G636D4FSZVEqKlr+K2j6bD9+4P9gHdev4az6lLp0VevdrrlzubhJV7UGHGRqRbV
1566178BYnMUkw==
1567""".decode("base64").decode("zlib")
1568
1569##file distribute_setup.py
1570DISTRIBUTE_SETUP_PY = """
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
1650""".decode("base64").decode("zlib")
1651
1652##file activate.sh
1653ACTIVATE_SH = """
1654eJytVU1v4jAQPW9+xTT0ANVS1GsrDlRFAqmFqmG72m0rY5IJsRRslDiktNr/vuMQ8tFQpNU2B4I9
1655H36eeW/SglkgYvBFiLBKYg0LhCRGD1KhA7BjlUQuwkLIHne12HCNNpz5kVrBgsfBmdWCrUrA5VIq
1656DVEiQWjwRISuDreW5eE+CtodeLeAnhZEGKMGFXqAciMiJVcoNWx4JPgixDjzEj48QVeCfcqmtzfs
1657cfww+zG4ZfeD2ciGF7gCHaDMPM1jtvuHXAsPfF2rSGeOxV4iDY5GUGb3xVEYv2aj6WQ0vRseAlMY
1658G5DKsAawwnQUXt2LQOYlzZoYByqhonqoqfxZf4BLD97i4DukgXADCPgGgdOLTK5arYxZB1xnrc9T
1659EQFcHoZEAa1gSQioo/TPV5FZrDlxJA+NzwF+Ek1UonOzFnKZp6k5mgLBqSkuuAGXS4whJb5xz/xs
1660wXCHjiVerAk5eh9Kfz1wqOldtVv9dkbscfjgjKeTA8XPrtaNauX5rInOxaHuOReNtpFjo1/OxdFG
16615eY9hJ3L3jqcPJbATggXAemDLZX0MNZRYjSDH7C1wMHQh73DyYfTu8a0F9v+6D8W6XNnF1GEIXW/
1662JrSKPOtnW1YFat9mrLJkzLbyIlTvYzV0RGXcaTBfVLx7jF2PJ2wyuBsydpm7VSVa4C4Zb6pFO2TR
1663huypCEPwuQjNftUrNl6GsYZzuFrrLdC9iJjQ3omAPBbcI2lsU77tUD43kw1NPZhTrnZWzuQKLomx
1664Rd4OXM1ByExVVkmoTwfBJ7Lt10Iq1Kgo23Bmd8Ib1KrGbsbO4Pp2yO4fpnf3s6MnZiwuiJuls1/L
1665Pu4yUCvhpA+vZaJvWWDTr0yFYYyVnHMqCEq+QniuYX225xmnzRENjbXACF3wkCYNVZ1mBwxoR9Iw
1666WAo3/36oSOTfgjwEEQKt15e9Xpqm52+oaXxszmnE9GLl65RH2OMmS6+u5acKxDmlPgj2eT5/gQOX
1667LLK0j1y0Uwbmn438VZkVpqlfNKa/YET/53j+99G8H8tUhr9ZSXs2
1668""".decode("base64").decode("zlib")
1669
1670##file activate.fish
1671ACTIVATE_FISH = """
1672eJydVm1v4jgQ/s6vmA1wBxUE7X2stJVYlVWR2lK13d6d9laRk0yIr8HmbIe0++tvnIQQB9pbXT5A
1673Ys/LM55nZtyHx5RrSHiGsMm1gRAh1xhDwU0Kng8hFzMWGb5jBv2E69SDs0TJDdj3MxilxmzPZzP7
1674pVPMMl+q9bjXh1eZQ8SEkAZULoAbiLnCyGSvvV6SC7IoBcS4Nw0wjcFbvJDcjiuTswzFDpiIQaHJ
1675lQAjQUi1YRmUboC2uZJig8J4PaCnT5IaDcgsbm/CjinOwgx1KcUTMEhhTgV4g2B1fRk8Le8fv86v
1676g7v545UHpZB9rKnp+gXsMhxLunIIpwVQxP/l9c/Hq9Xt1epm4R27bva6AJqN92G4YhbMG2i+LB+u
1677grv71c3dY7B6WtzfLy9bePbp0taDTXSwJQJszUnnp0y57mvpPcrF7ZODyhswtd59+/jdgw+fwBNS
1678xLSscksUPIDqwwNmCez3PpxGeyBYg6HE0YdcWBxcKczYzuVJi5Wu915vn5oWePCCoPUZBN5B7IgV
1679MCi54ZDLG7TUZ0HweXkb3M5vFmSpFm/gthhBx0UrveoPpv9AJ9unIbQYdUoe21bKg2q48sPFGVwu
1680H+afrxd1qvclaNlRFyh1EQ2sSccEuNAGWQwysfVpz1tPajUqbqJUnEcIJkWo6OXDaodK8ZiLdbmM
1681L1wb+9H0D+pcyPSrX5u5kgWSygRYXCnJUi/KKcuU4cqsAyTKZBiissLc7NFwizvjxtieKBVCIdWz
1682fzilzPaYyljZN0cGN1v7NnaIPNCGmVy3GKuJaQ6iVjE1Qfm+36hglErwmnAD8hu0dDy4uICBA8ZV
1683pQr/q/+O0KFW2kjelu9Dgb9SDBsWV4F4x5CswgS0zBVlk5tDMP5bVtUGpslbm81Lu2sdKq7uNMGh
1684MVQ4fy9xhogC1lS5guhISa0DlBWv0O8odT6/LP+4WZzDV6FzIkEqC0uolGZSZoMnlpxplmD2euaT
1685O4hkTpPnbztDccey0bhjDaBIqaWQa0uwEtQEwtyU56i4fq54F9IE3ORR6mKriODM4XOYZwaVYLYz
16867SPbKkz4i7VkB6/Ot1upDE3znNqYKpM8raa0Bx8vfvntJ32UENsM4aI6gJL+jJwhxhh3jVIDOcpi
1687m0r2hmEtS8XXXNBk71QCDXTBNhhPiHX2LtHkrVIlhoEshH/EZgdq53Eirqs5iFKMnkOmqZTtr3Xq
1688djvPTWZT4S3NT5aVLgurMPUWI07BRVYqkQrmtCKohNY8qu9EdACoT6ki0a66XxVF4f9AQ3W38yO5
1689mWmZmIIpnDFrbXakvKWeZhLwhvrbUH8fahhqD0YUcBDJjEBMQwiznE4y5QbHrbhHBOnUAYzb2tVN
1690jJa65e+eE2Ya30E2GurxUP8ssA6e/wOnvo3V78d3vTcvMB3n7l3iX1JXWqk=
1691""".decode("base64").decode("zlib")
1692
1693##file activate.csh
1694ACTIVATE_CSH = """
1695eJx9U11vmzAUffevOCVRu+UB9pws29Kl0iq1aVWllaZlcgxciiViItsQdb9+xiQp+dh4QOB7Pu49
1696XHqY59IgkwVhVRmLmFAZSrGRNkdgykonhFiqSCRW1sJSmJg8wCDT5QrucRCyHn6WFRKhVGmhKwVp
1697kUpNiS3emup3TY6XIn7DVNQyJUwlrgthJD6n/iCNv72uhCzCpFx9CRkThRQGKe08cWXJ9db/yh/u
1698pvzl9mn+PLnjj5P5D1yM8QmXlzBkSdXwZ0H/BBc0mEo5FE5qI2jKhclHOOvy9HD/OO/6YO1mX9vx
1699sY0H/tPIV0dtqel0V7iZvWyNg8XFcBA0ToEqVeqOdNUEQFvN41SumAv32VtJrakQNSmLWmgp4oJM
1700yDoBHgoydtoEAs47r5wHHnUal5vbJ8oOI+9wI86vb2d8Nrm/4Xy4RZ8R85E4uTZPB5EZPnTaaAGu
1701E59J8BE2J8XgrkbLeXMlVoQxznEYFYY8uFFdxsKQRx90Giwx9vSueHP1YNaUSFG4vTaErNSYuBOF
1702lXiVyXa9Sy3JdClEyK1dD6Nos9mEf8iKlOpmqSNTZnYjNEWiUYn2pKNB3ttcLJ3HmYYXy6Un76f7
1703r8rRsC1TpTJj7f19m5sUf/V3Ir+x/yjtLu8KjLX/CmN/AcVGUUo=
1704""".decode("base64").decode("zlib")
1705
1706##file activate.bat
1707ACTIVATE_BAT = """
1708eJyFUkEKgzAQvAfyhz0YaL9QEWpRqlSjWGspFPZQTevFHOr/adQaU1GaUzI7Mzu7ZF89XhKkEJS8
1709qxaKMMsvboQ+LxxE44VICSW1gEa2UFaibqoS0iyJ0xw2lIA6nX5AHCu1jpRsv5KRjknkac9VLVug
1710sX9mtzxIeJDE/mg4OGp47qoLo3NHX2jsMB3AiDht5hryAUOEifoTdCXbSh7V0My2NMq/Xbh5MEjU
1711ZT63gpgNT9lKOJ/CtHsvT99re3pX303kydn4HeyOeAg5cjf2EW1D6HOPkg9NGKhu
1712""".decode("base64").decode("zlib")
1713
1714##file deactivate.bat
1715DEACTIVATE_BAT = """
1716eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
1717FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL
1718i2dASrm4rFz9XLgAwJNbyQ==
1719""".decode("base64").decode("zlib")
1720
1721##file distutils-init.py
1722DISTUTILS_INIT = """
1723eJytV92L4zYQf9dfMU0ottuse/TeFkKh3MvC0Ydy0IdlMVpbTtR1JCMpm+T++s5Y/pBs53oPZ1hQ
1724pPnSb34zo5WnVhsH2jLpV/Y2Li/cKKkOFoYN3Za6ErAdFtKC0g44vEvjzrwR6h1Oujo3YgdWw0VA
1725yRWcLUo6cBpqqSpwRwHWVY18ZRB9W3jq3HDlfoIvqK7NG2gF7a297VANvZ3O1sGrQI/eDe5yB0ZY
1726WQkLUpHxhVX09NDe3FGr31BL1lJUD9f8ln+FShpROm1ujOFS8ZOAPUKRt9wd836Hjqw7O9nYgvYD
1727iX+1VOlMPPXQ5EVRy0YURbaDZDSQZEzWo7rS5kSLNHaQwX4RRLrQGe1nj92Fh1zltEhHDDZfEO0g
1728O6MraHn5xg8IpYOfLfC2FdxYShLC64EES4A0uuROYhq49Zs368RpMvTHJmOiscKHUXRXKIpcKiuM
1729Sz/sYHa7TkxcRYkkEhN8HZaxKCJXFFJJh+baW5JluRG8SjM20JHEA9qWWtXywBjbbvF2rjzC61k2
1730VSGuDibTUGlhVeLgTekLHPEP73wQrrscUsUGrPCGjkTCC1JXXyw8EJWP3FSUZY8IiSCCRp97dnfO
1731RUUx5a0RtbxSzLX/3XBXYxIpyQka/fh74pGrjQ5QzUt9OnFV5dMV+otOG5gQjctxozNTNtzaSSiN
1732JHqu0FeJmsqRN/KrKHRLGbaQWtHUgRB9FDfu5giN4eZWIDqWCv8vrcTjrNZgRXQPzy+RmGjQpLRI
1733EKz0UqQLlR28ciusM8jn7PtcLPZy2zbSDeyyos0iO+ybBgPyRvSk/CEFm8IndQebz8iXTRbbjhDP
17345xh7iJfBrKd/Nenjj6Jvgp2B+W7AnP102BXH5IZWPV3tI2MUOvXowpdS12IIXhLLP0lKyeuZrpEv
1735pFhPqHg3JFTd1cceVp0EsPgGU0wFO2u4iyYRoFYfEm9kG/RZcUUBm87t9mFtx9iCtC9kx4Rt4R8a
1736OdgzSt40vtyFecAZZ8BfCOhCrC8djMGPFaz2Vlt5TSZCk053+37wbLDLRXfZ+F45NtdVpVWdudSC
1737xgODI8EsiLoTl5aO0lhoigX7GHZDHAY4LxoMIu1gXPYPksmFquxF4uRKZhEnKzXu82HESb+LlNQz
1738Fh/RvFJVuhK+Ee5slBdj30FcRGdJ5rhKxtkyKxWcGoV/WOCYKqkNDYJ5fNQVx3g400tpJBS2FSU+
1739Tco9ss8nZ08dtscGQfSby87b73fOw+4UgrEMNnY6uMzYvSDxPVPpsij6+l0/ZPfuH0Iz010giY34
1740HpL0ZLyLJB4ukaQRU+GwptO7yIZCQE33B0K9iCqO6X+AR4n7wAeH68DPkJzpTsD3x+/cj9LIVHC2
1741An1wmv7CzWHoqR02vb0VL73siP+3nkX0YbQ0l9f6WDyOm24cj3rxO2MMip6kpcu6VCefn/789PR3
17420v0fg21sFIp70rj9PCi8YDRDXFucym/43qN+iENh1Jy/dIIIqF3OIkDvBMsdx+huWv8Kz73vl8g5
1743WQ3JOGqwu3lb4dfKKbvLigXDQsb8B/xt39Q=
1744""".decode("base64").decode("zlib")
1745
1746##file distutils.cfg
1747DISTUTILS_CFG = """
1748eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
1749xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
17509FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
1751""".decode("base64").decode("zlib")
1752
1753##file activate_this.py
1754ACTIVATE_THIS = """
1755eJyNUlGL2zAMfvevEBlHEujSsXsL9GGDvW1jD3sZpQQ3Ua7aJXawnbT595Ocpe0dO5ghseVP+vRJ
1756VpIkn2cYPZknwAvWLXWYhRP5Sk4baKgOWRWNqtpdgTyH2Y5wpq5Tug406YAgKEzkwqg7NBPwR86a
1757Hk0olPopaK0NHJHzYQPnE5rI0o8+yBUwiBfyQcT8mMPJGiAT0A0O+b8BY4MKJ7zPcSSzHaKrSpJE
1758qeDmUgGvVbPCS41DgO+6xy/OWbfAThMn/OQ9ukDWRCSLiKzk1yrLjWapq6NnvHUoHXQ4bYPdrsVX
17594lQMc/q6ZW975nmSK+oH6wL42a9H65U6aha342Mh0UVDzrD87C1bH73s16R5zsStkBZDp0NrXQ+7
1760HaRnMo8f06UBnljKoOtn/YT+LtdvSyaT/BtIv9KR60nF9f3qmuYKO4//T9ItJMsjPfgUHqKwCZ3n
1761xu/Lx8M/UvCLTxW7VULHxB1PRRbrYfvWNY5S8it008jOjcleaMqVBDnUXcWULV2YK9JEQ92OfC96
17621Tv4ZicZZZ7GpuEpZbbeQ7DxquVx5hdqoyFSSmXwfC90f1Dc7hjFs/tK99I0fpkI8zSLy4tSy+sI
17633vMWehjQNJmE5VePlZbL61nzX3S93ZcfDqznnkb9AZ3GWJU=
1764""".decode("base64").decode("zlib")
1765
1766if __name__ == '__main__':
1767 main()
1768
1769## TODO:
1770## Copy python.exe.manifest
1771## Monkeypatch distutils.sysconfig