source: coopr.misc/trunk/util/coopr_install @ 2972

Last change on this file since 2972 was 2972, checked in by wehart, 11 years ago

Bug fix to recognize that a stable directory does
not contain versioned subdirectories.

  • Property svn:executable set to *
File size: 162.6 KB
Line 
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.4.9"
8
9import sys
10import os
11import optparse
12import re
13import shutil
14import logging
15import distutils.sysconfig
16try:
17    import subprocess
18except ImportError, e:
19    if sys.version_info <= (2, 3):
20        print 'ERROR: %s' % e
21        print 'ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.'
22        print 'If you copy subprocess.py from a newer version of Python this script will probably work'
23        sys.exit(101)
24    else:
25        raise
26try:
27    set
28except NameError:
29    from sets import Set as set
30
31join = os.path.join
32py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
33is_jython = sys.platform.startswith('java')
34expected_exe = is_jython and 'jython' or 'python'
35
36REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath',
37                    'fnmatch', 'locale', 'encodings', 'codecs',
38                    'stat', 'UserDict', 'readline', 'copy_reg', 'types',
39                    're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile',
40                    'lib-dynload', 'config', 'zlib']
41
42if sys.version_info[:2] >= (2, 6):
43    REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc'])
44if sys.version_info[:2] <= (2, 3):
45    REQUIRED_MODULES.extend(['sets', '__future__'])
46
47class Logger(object):
48
49    """
50    Logging object for use in command-line script.  Allows ranges of
51    levels, to avoid some redundancy of displayed information.
52    """
53
54    DEBUG = logging.DEBUG
55    INFO = logging.INFO
56    NOTIFY = (logging.INFO+logging.WARN)/2
57    WARN = WARNING = logging.WARN
58    ERROR = logging.ERROR
59    FATAL = logging.FATAL
60
61    LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL]
62
63    def __init__(self, consumers):
64        self.consumers = consumers
65        self.indent = 0
66        self.in_progress = None
67        self.in_progress_hanging = False
68
69    def debug(self, msg, *args, **kw):
70        self.log(self.DEBUG, msg, *args, **kw)
71    def info(self, msg, *args, **kw):
72        self.log(self.INFO, msg, *args, **kw)
73    def notify(self, msg, *args, **kw):
74        self.log(self.NOTIFY, msg, *args, **kw)
75    def warn(self, msg, *args, **kw):
76        self.log(self.WARN, msg, *args, **kw)
77    def error(self, msg, *args, **kw):
78        self.log(self.WARN, msg, *args, **kw)
79    def fatal(self, msg, *args, **kw):
80        self.log(self.FATAL, msg, *args, **kw)
81    def log(self, level, msg, *args, **kw):
82        if args:
83            if kw:
84                raise TypeError(
85                    "You may give positional or keyword arguments, not both")
86        args = args or kw
87        rendered = None
88        for consumer_level, consumer in self.consumers:
89            if self.level_matches(level, consumer_level):
90                if (self.in_progress_hanging
91                    and consumer in (sys.stdout, sys.stderr)):
92                    self.in_progress_hanging = False
93                    sys.stdout.write('\n')
94                    sys.stdout.flush()
95                if rendered is None:
96                    if args:
97                        rendered = msg % args
98                    else:
99                        rendered = msg
100                    rendered = ' '*self.indent + rendered
101                if hasattr(consumer, 'write'):
102                    consumer.write(rendered+'\n')
103                else:
104                    consumer(rendered)
105
106    def start_progress(self, msg):
107        assert not self.in_progress, (
108            "Tried to start_progress(%r) while in_progress %r"
109            % (msg, self.in_progress))
110        if self.level_matches(self.NOTIFY, self._stdout_level()):
111            sys.stdout.write(msg)
112            sys.stdout.flush()
113            self.in_progress_hanging = True
114        else:
115            self.in_progress_hanging = False
116        self.in_progress = msg
117
118    def end_progress(self, msg='done.'):
119        assert self.in_progress, (
120            "Tried to end_progress without start_progress")
121        if self.stdout_level_matches(self.NOTIFY):
122            if not self.in_progress_hanging:
123                # Some message has been printed out since start_progress
124                sys.stdout.write('...' + self.in_progress + msg + '\n')
125                sys.stdout.flush()
126            else:
127                sys.stdout.write(msg + '\n')
128                sys.stdout.flush()
129        self.in_progress = None
130        self.in_progress_hanging = False
131
132    def show_progress(self):
133        """If we are in a progress scope, and no log messages have been
134        shown, write out another '.'"""
135        if self.in_progress_hanging:
136            sys.stdout.write('.')
137            sys.stdout.flush()
138
139    def stdout_level_matches(self, level):
140        """Returns true if a message at this level will go to stdout"""
141        return self.level_matches(level, self._stdout_level())
142
143    def _stdout_level(self):
144        """Returns the level that stdout runs at"""
145        for level, consumer in self.consumers:
146            if consumer is sys.stdout:
147                return level
148        return self.FATAL
149
150    def level_matches(self, level, consumer_level):
151        """
152        >>> l = Logger()
153        >>> l.level_matches(3, 4)
154        False
155        >>> l.level_matches(3, 2)
156        True
157        >>> l.level_matches(slice(None, 3), 3)
158        False
159        >>> l.level_matches(slice(None, 3), 2)
160        True
161        >>> l.level_matches(slice(1, 3), 1)
162        True
163        >>> l.level_matches(slice(2, 3), 1)
164        False
165        """
166        if isinstance(level, slice):
167            start, stop = level.start, level.stop
168            if start is not None and start > consumer_level:
169                return False
170            if stop is not None or stop <= consumer_level:
171                return False
172            return True
173        else:
174            return level >= consumer_level
175
176    #@classmethod
177    def level_for_integer(cls, level):
178        levels = cls.LEVELS
179        if level < 0:
180            return levels[0]
181        if level >= len(levels):
182            return levels[-1]
183        return levels[level]
184
185    level_for_integer = classmethod(level_for_integer)
186
187def mkdir(path):
188    if not os.path.exists(path):
189        logger.info('Creating %s', path)
190        os.makedirs(path)
191    else:
192        logger.info('Directory %s already exists', path)
193
194def copyfile(src, dest, symlink=True):
195    if not os.path.exists(src):
196        # Some bad symlink in the src
197        logger.warn('Cannot find file %s (bad symlink)', src)
198        return
199    if os.path.exists(dest):
200        logger.debug('File %s already exists', dest)
201        return
202    if not os.path.exists(os.path.dirname(dest)):
203        logger.info('Creating parent directories for %s' % os.path.dirname(dest))
204        os.makedirs(os.path.dirname(dest))
205    if symlink and hasattr(os, 'symlink'):
206        logger.info('Symlinking %s', dest)
207        os.symlink(os.path.abspath(src), dest)
208    else:
209        logger.info('Copying to %s', dest)
210        if os.path.isdir(src):
211            shutil.copytree(src, dest, True)
212        else:
213            shutil.copy2(src, dest)
214
215def writefile(dest, content, overwrite=True):
216    if not os.path.exists(dest):
217        logger.info('Writing %s', dest)
218        f = open(dest, 'wb')
219        f.write(content)
220        f.close()
221        return
222    else:
223        f = open(dest, 'rb')
224        c = f.read()
225        f.close()
226        if c != content:
227            if not overwrite:
228                logger.notify('File %s exists with different content; not overwriting', dest)
229                return
230            logger.notify('Overwriting %s with new content', dest)
231            f = open(dest, 'wb')
232            f.write(content)
233            f.close()
234        else:
235            logger.info('Content %s already in place', dest)
236
237def rmtree(dir):
238    if os.path.exists(dir):
239        logger.notify('Deleting tree %s', dir)
240        shutil.rmtree(dir)
241    else:
242        logger.info('Do not need to delete %s; already gone', dir)
243
244def make_exe(fn):
245    if hasattr(os, 'chmod'):
246        oldmode = os.stat(fn).st_mode & 07777
247        newmode = (oldmode | 0555) & 07777
248        os.chmod(fn, newmode)
249        logger.info('Changed mode of %s to %s', fn, oct(newmode))
250
251def _find_file(filename, dirs):
252    for dir in dirs:
253        if os.path.exists(join(dir, filename)):
254            return join(dir, filename)
255    return filename
256
257def _install_req(py_executable, unzip=False, distribute=False):
258    if not distribute:
259        setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3]
260        project_name = 'setuptools'
261        bootstrap_script = EZ_SETUP_PY
262        source = None
263    else:
264        setup_fn = None
265        source = 'distribute-0.6.8.tar.gz'
266        project_name = 'distribute'
267        bootstrap_script = DISTRIBUTE_SETUP_PY
268        try:
269            # check if the global Python has distribute installed or plain
270            # setuptools
271            import pkg_resources
272            if not hasattr(pkg_resources, '_distribute'):
273                location = os.path.dirname(pkg_resources.__file__)
274                logger.notify("A globally installed setuptools was found (in %s)" % location)
275                logger.notify("Use the --no-site-packages option to use distribute in "
276                              "the virtualenv.")
277        except ImportError:
278            pass
279
280    search_dirs = file_search_dirs()
281
282    if setup_fn is not None:
283        setup_fn = _find_file(setup_fn, search_dirs)
284
285    if source is not None:
286        source = _find_file(source, search_dirs)
287
288    if is_jython and os._name == 'nt':
289        # Jython's .bat sys.executable can't handle a command line
290        # argument with newlines
291        import tempfile
292        fd, ez_setup = tempfile.mkstemp('.py')
293        os.write(fd, bootstrap_script)
294        os.close(fd)
295        cmd = [py_executable, ez_setup]
296    else:
297        cmd = [py_executable, '-c', bootstrap_script]
298    if unzip:
299        cmd.append('--always-unzip')
300    env = {}
301    if logger.stdout_level_matches(logger.DEBUG):
302        cmd.append('-v')
303
304    old_chdir = os.getcwd()
305    if setup_fn is not None and os.path.exists(setup_fn):
306        logger.info('Using existing %s egg: %s' % (project_name, setup_fn))
307        cmd.append(setup_fn)
308        if os.environ.get('PYTHONPATH'):
309            env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH']
310        else:
311            env['PYTHONPATH'] = setup_fn
312    else:
313        # the source is found, let's chdir
314        if source is not None and os.path.exists(source):
315            os.chdir(os.path.dirname(source))
316        else:
317            logger.info('No %s egg found; downloading' % project_name)
318        cmd.extend(['--always-copy', '-U', project_name])
319    logger.start_progress('Installing %s...' % project_name)
320    logger.indent += 2
321    cwd = None
322    if project_name == 'distribute':
323        env['DONT_PATCH_SETUPTOOLS'] = 'true'
324
325    def _filter_ez_setup(line):
326        return filter_ez_setup(line, project_name)
327
328    if not os.access(os.getcwd(), os.W_OK):
329        cwd = '/tmp'
330        if source is not None and os.path.exists(source):
331            # the current working dir is hostile, let's copy the
332            # tarball to /tmp
333            target = os.path.join(cwd, os.path.split(source)[-1])
334            shutil.copy(source, target)
335    try:
336        call_subprocess(cmd, show_stdout=False,
337                        filter_stdout=_filter_ez_setup,
338                        extra_env=env,
339                        cwd=cwd)
340    finally:
341        logger.indent -= 2
342        logger.end_progress()
343        if os.getcwd() != old_chdir:
344            os.chdir(old_chdir)
345        if is_jython and os._name == 'nt':
346            os.remove(ez_setup)
347
348def file_search_dirs():
349    here = os.path.dirname(os.path.abspath(__file__))
350    dirs = ['.', here,
351            join(here, 'virtualenv_support')]
352    if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv':
353        # Probably some boot script; just in case virtualenv is installed...
354        try:
355            import virtualenv
356        except ImportError:
357            pass
358        else:
359            dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support'))
360    return [d for d in dirs if os.path.isdir(d)]
361
362def install_setuptools(py_executable, unzip=False):
363    _install_req(py_executable, unzip)
364
365def install_distribute(py_executable, unzip=False):
366    _install_req(py_executable, unzip, distribute=True)
367
368_pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I)
369def install_pip(py_executable):
370    filenames = []
371    for dir in file_search_dirs():
372        filenames.extend([join(dir, fn) for fn in os.listdir(dir)
373                          if _pip_re.search(fn)])
374    filenames.sort(key=lambda x: os.path.basename(x).lower())
375    if not filenames:
376        filename = 'pip'
377    else:
378        filename = filenames[-1]
379    easy_install_script = 'easy_install'
380    if sys.platform == 'win32':
381        easy_install_script = 'easy_install-script.py'
382    cmd = [py_executable, join(os.path.dirname(py_executable), easy_install_script), filename]
383    if filename == 'pip':
384        logger.info('Installing pip from network...')
385    else:
386        logger.info('Installing %s' % os.path.basename(filename))
387    logger.indent += 2
388    def _filter_setup(line):
389        return filter_ez_setup(line, 'pip')
390    try:
391        call_subprocess(cmd, show_stdout=False,
392                        filter_stdout=_filter_setup)
393    finally:
394        logger.indent -= 2
395
396def filter_ez_setup(line, project_name='setuptools'):
397    if not line.strip():
398        return Logger.DEBUG
399    if project_name == 'distribute':
400        for prefix in ('Extracting', 'Now working', 'Installing', 'Before',
401                       'Scanning', 'Setuptools', 'Egg', 'Already',
402                       'running', 'writing', 'reading', 'installing',
403                       'creating', 'copying', 'byte-compiling', 'removing',
404                       'Processing'):
405            if line.startswith(prefix):
406                return Logger.DEBUG
407        return Logger.DEBUG
408    for prefix in ['Reading ', 'Best match', 'Processing setuptools',
409                   'Copying setuptools', 'Adding setuptools',
410                   'Installing ', 'Installed ']:
411        if line.startswith(prefix):
412            return Logger.DEBUG
413    return Logger.INFO
414
415def main():
416    parser = optparse.OptionParser(
417        version=virtualenv_version,
418        usage="%prog [OPTIONS] DEST_DIR")
419
420    parser.add_option(
421        '-v', '--verbose',
422        action='count',
423        dest='verbose',
424        default=0,
425        help="Increase verbosity")
426
427    parser.add_option(
428        '-q', '--quiet',
429        action='count',
430        dest='quiet',
431        default=0,
432        help='Decrease verbosity')
433
434    parser.add_option(
435        '-p', '--python',
436        dest='python',
437        metavar='PYTHON_EXE',
438        help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 '
439        'interpreter to create the new environment.  The default is the interpreter that '
440        'virtualenv was installed with (%s)' % sys.executable)
441
442    parser.add_option(
443        '--clear',
444        dest='clear',
445        action='store_true',
446        help="Clear out the non-root install and start from scratch")
447
448    parser.add_option(
449        '--no-site-packages',
450        dest='no_site_packages',
451        action='store_true',
452        help="Don't give access to the global site-packages dir to the "
453             "virtual environment")
454
455    parser.add_option(
456        '--unzip-setuptools',
457        dest='unzip_setuptools',
458        action='store_true',
459        help="Unzip Setuptools or Distribute when installing it")
460
461    parser.add_option(
462        '--relocatable',
463        dest='relocatable',
464        action='store_true',
465        help='Make an EXISTING virtualenv environment relocatable.  '
466        'This fixes up scripts and makes all .pth files relative')
467
468    parser.add_option(
469        '--distribute',
470        dest='use_distribute',
471        action='store_true',
472        help='Use Distribute instead of Setuptools. Set environ variable'
473        'VIRTUALENV_USE_DISTRIBUTE to make it the default ')
474
475    if 'extend_parser' in globals():
476        extend_parser(parser)
477
478    options, args = parser.parse_args()
479
480    global logger
481
482    if 'adjust_options' in globals():
483        adjust_options(options, args)
484
485    verbosity = options.verbose - options.quiet
486    logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
487
488    if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
489        env = os.environ.copy()
490        interpreter = resolve_interpreter(options.python)
491        if interpreter == sys.executable:
492            logger.warn('Already using interpreter %s' % interpreter)
493        else:
494            logger.notify('Running virtualenv with interpreter %s' % interpreter)
495            env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true'
496            file = __file__
497            if file.endswith('.pyc'):
498                file = file[:-1]
499            os.execvpe(interpreter, [interpreter, file] + sys.argv[1:], env)
500
501    if not args:
502        print 'You must provide a DEST_DIR'
503        parser.print_help()
504        sys.exit(2)
505    if len(args) > 1:
506        print 'There must be only one argument: DEST_DIR (you gave %s)' % (
507            ' '.join(args))
508        parser.print_help()
509        sys.exit(2)
510
511    home_dir = args[0]
512
513    if os.environ.get('WORKING_ENV'):
514        logger.fatal('ERROR: you cannot run virtualenv while in a workingenv')
515        logger.fatal('Please deactivate your workingenv, then re-run this script')
516        sys.exit(3)
517
518    if 'PYTHONHOME' in os.environ:
519        logger.warn('PYTHONHOME is set.  You *must* activate the virtualenv before using it')
520        del os.environ['PYTHONHOME']
521
522    if options.relocatable:
523        make_environment_relocatable(home_dir)
524        return
525
526    create_environment(home_dir, site_packages=not options.no_site_packages, clear=options.clear,
527                       unzip_setuptools=options.unzip_setuptools,
528                       use_distribute=options.use_distribute)
529    if 'after_install' in globals():
530        after_install(options, home_dir)
531
532def call_subprocess(cmd, show_stdout=True,
533                    filter_stdout=None, cwd=None,
534                    raise_on_returncode=True, extra_env=None):
535    cmd_parts = []
536    for part in cmd:
537        if len(part) > 40:
538            part = part[:30]+"..."+part[-5:]
539        if ' ' in part or '\n' in part or '"' in part or "'" in part:
540            part = '"%s"' % part.replace('"', '\\"')
541        cmd_parts.append(part)
542    cmd_desc = ' '.join(cmd_parts)
543    if show_stdout:
544        stdout = None
545    else:
546        stdout = subprocess.PIPE
547    logger.debug("Running command %s" % cmd_desc)
548    if extra_env:
549        env = os.environ.copy()
550        env.update(extra_env)
551    else:
552        env = None
553    try:
554        proc = subprocess.Popen(
555            cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout,
556            cwd=cwd, env=env)
557    except Exception, e:
558        logger.fatal(
559            "Error %s while executing command %s" % (e, cmd_desc))
560        raise
561    all_output = []
562    if stdout is not None:
563        stdout = proc.stdout
564        while 1:
565            line = stdout.readline()
566            if not line:
567                break
568            line = line.rstrip()
569            all_output.append(line)
570            if filter_stdout:
571                level = filter_stdout(line)
572                if isinstance(level, tuple):
573                    level, line = level
574                logger.log(level, line)
575                if not logger.stdout_level_matches(level):
576                    logger.show_progress()
577            else:
578                logger.info(line)
579    else:
580        proc.communicate()
581    proc.wait()
582    if proc.returncode:
583        if raise_on_returncode:
584            if all_output:
585                logger.notify('Complete output from command %s:' % cmd_desc)
586                logger.notify('\n'.join(all_output) + '\n----------------------------------------')
587            raise OSError(
588                "Command %s failed with error code %s"
589                % (cmd_desc, proc.returncode))
590        else:
591            logger.warn(
592                "Command %s had error code %s"
593                % (cmd_desc, proc.returncode))
594
595
596def create_environment(home_dir, site_packages=True, clear=False,
597                       unzip_setuptools=False, use_distribute=False):
598    """
599    Creates a new environment in ``home_dir``.
600
601    If ``site_packages`` is true (the default) then the global
602    ``site-packages/`` directory will be on the path.
603
604    If ``clear`` is true (default False) then the environment will
605    first be cleared.
606    """
607    home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir)
608
609    py_executable = os.path.abspath(install_python(
610        home_dir, lib_dir, inc_dir, bin_dir,
611        site_packages=site_packages, clear=clear))
612
613    install_distutils(lib_dir, home_dir)
614
615    if use_distribute or os.environ.get('VIRTUALENV_USE_DISTRIBUTE'):
616        install_distribute(py_executable, unzip=unzip_setuptools)
617    else:
618        install_setuptools(py_executable, unzip=unzip_setuptools)
619
620    install_pip(py_executable)
621
622    install_activate(home_dir, bin_dir)
623
624def path_locations(home_dir):
625    """Return the path locations for the environment (where libraries are,
626    where scripts go, etc)"""
627    # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its
628    # prefix arg is broken: http://bugs.python.org/issue3386
629    if sys.platform == 'win32':
630        # Windows has lots of problems with executables with spaces in
631        # the name; this function will remove them (using the ~1
632        # format):
633        mkdir(home_dir)
634        if ' ' in home_dir:
635            try:
636                pass
637            except ImportError:
638                print 'Error: the path "%s" has a space in it' % home_dir
639                pass
640                print '  http://sourceforge.net/projects/pywin32/'
641                sys.exit(3)
642            pass
643        lib_dir = join(home_dir, 'Lib')
644        inc_dir = join(home_dir, 'Include')
645        bin_dir = join(home_dir, 'Scripts')
646    elif is_jython:
647        lib_dir = join(home_dir, 'Lib')
648        inc_dir = join(home_dir, 'Include')
649        bin_dir = join(home_dir, 'bin')
650    else:
651        lib_dir = join(home_dir, 'lib', py_version)
652        inc_dir = join(home_dir, 'include', py_version)
653        bin_dir = join(home_dir, 'bin')
654    return home_dir, lib_dir, inc_dir, bin_dir
655
656def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
657    """Install just the base environment, no distutils patches etc"""
658    if sys.executable.startswith(bin_dir):
659        print 'Please use the *system* python to run this script'
660        return
661
662    if clear:
663        rmtree(lib_dir)
664        # pyutilib.virtualenv: ignoring comment
665        ## Maybe it should delete everything with #!/path/to/venv/python in it
666        logger.notify('Not deleting %s', bin_dir)
667
668    if hasattr(sys, 'real_prefix'):
669        logger.notify('Using real prefix %r' % sys.real_prefix)
670        prefix = sys.real_prefix
671    else:
672        prefix = sys.prefix
673    mkdir(lib_dir)
674    fix_lib64(lib_dir)
675    stdlib_dirs = [os.path.dirname(os.__file__)]
676    if sys.platform == 'win32':
677        stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs'))
678    elif sys.platform == 'darwin':
679        stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages'))
680    for stdlib_dir in stdlib_dirs:
681        if not os.path.isdir(stdlib_dir):
682            continue
683        if hasattr(os, 'symlink'):
684            logger.info('Symlinking Python bootstrap modules')
685        else:
686            logger.info('Copying Python bootstrap modules')
687        logger.indent += 2
688        try:
689            for fn in os.listdir(stdlib_dir):
690                if fn != 'site-packages' and os.path.splitext(fn)[0] in REQUIRED_MODULES:
691                    copyfile(join(stdlib_dir, fn), join(lib_dir, fn))
692        finally:
693            logger.indent -= 2
694    mkdir(join(lib_dir, 'site-packages'))
695    writefile(join(lib_dir, 'site.py'), SITE_PY)
696    writefile(join(lib_dir, 'orig-prefix.txt'), prefix)
697    site_packages_filename = join(lib_dir, 'no-global-site-packages.txt')
698    if not site_packages:
699        writefile(site_packages_filename, '')
700    else:
701        if os.path.exists(site_packages_filename):
702            logger.info('Deleting %s' % site_packages_filename)
703            os.unlink(site_packages_filename)
704
705    stdinc_dir = join(prefix, 'include', py_version)
706    if os.path.exists(stdinc_dir):
707        copyfile(stdinc_dir, inc_dir)
708    else:
709        logger.debug('No include dir %s' % stdinc_dir)
710
711    if sys.exec_prefix != prefix:
712        if sys.platform == 'win32':
713            exec_dir = join(sys.exec_prefix, 'lib')
714        elif is_jython:
715            exec_dir = join(sys.exec_prefix, 'Lib')
716        else:
717            exec_dir = join(sys.exec_prefix, 'lib', py_version)
718        for fn in os.listdir(exec_dir):
719            copyfile(join(exec_dir, fn), join(lib_dir, fn))
720
721    if is_jython:
722        # Jython has either jython-dev.jar and javalib/ dir, or just
723        # jython.jar
724        for name in 'jython-dev.jar', 'javalib', 'jython.jar':
725            src = join(prefix, name)
726            if os.path.exists(src):
727                copyfile(src, join(home_dir, name))
728        # XXX: registry should always exist after Jython 2.5rc1
729        src = join(prefix, 'registry')
730        if os.path.exists(src):
731            copyfile(src, join(home_dir, 'registry'), symlink=False)
732        copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'),
733                 symlink=False)
734
735    mkdir(bin_dir)
736    py_executable = join(bin_dir, os.path.basename(sys.executable))
737    if 'Python.framework' in prefix:
738        if re.search(r'/Python(?:-32|-64)*$', py_executable):
739            # The name of the python executable is not quite what
740            # we want, rename it.
741            py_executable = os.path.join(
742                    os.path.dirname(py_executable), 'python')
743
744    logger.notify('New %s executable in %s', expected_exe, py_executable)
745    if sys.executable != py_executable:
746        # pyutilib.virtualenv: ignoring comment
747        executable = sys.executable
748        if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'):
749            # Cygwin misreports sys.executable sometimes
750            executable += '.exe'
751            py_executable += '.exe'
752            logger.info('Executable actually exists in %s' % executable)
753        shutil.copyfile(executable, py_executable)
754        make_exe(py_executable)
755        if sys.platform == 'win32' or sys.platform == 'cygwin':
756            pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe')
757            if os.path.exists(pythonw):
758                logger.info('Also created pythonw.exe')
759                shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe'))
760
761    if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
762        secondary_exe = os.path.join(os.path.dirname(py_executable),
763                                     expected_exe)
764        py_executable_ext = os.path.splitext(py_executable)[1]
765        if py_executable_ext == '.exe':
766            # python2.4 gives an extension of '.4' :P
767            secondary_exe += py_executable_ext
768        if os.path.exists(secondary_exe):
769            logger.warn('Not overwriting existing %s script %s (you must use %s)'
770                        % (expected_exe, secondary_exe, py_executable))
771        else:
772            logger.notify('Also creating executable in %s' % secondary_exe)
773            shutil.copyfile(sys.executable, secondary_exe)
774            make_exe(secondary_exe)
775
776    if 'Python.framework' in prefix:
777        logger.debug('MacOSX Python framework detected')
778
779        # Make sure we use the the embedded interpreter inside
780        # the framework, even if sys.executable points to
781        # the stub executable in ${sys.prefix}/bin
782        # See http://groups.google.com/group/python-virtualenv/
783        #                              browse_thread/thread/17cab2f85da75951
784        shutil.copy(
785                os.path.join(
786                    prefix, 'Resources/Python.app/Contents/MacOS/%s' % os.path.basename(sys.executable)),
787                py_executable)
788
789        # Copy the framework's dylib into the virtual
790        # environment
791        virtual_lib = os.path.join(home_dir, '.Python')
792
793        if os.path.exists(virtual_lib):
794            os.unlink(virtual_lib)
795        copyfile(
796            os.path.join(prefix, 'Python'),
797            virtual_lib)
798
799        # And then change the install_name of the copied python executable
800        try:
801            call_subprocess(
802                ["install_name_tool", "-change",
803                 os.path.join(prefix, 'Python'),
804                 '@executable_path/../.Python',
805                 py_executable])
806        except:
807            logger.fatal(
808                "Could not call install_name_tool -- you must have Apple's development tools installed")
809            raise
810
811        # Some tools depend on pythonX.Y being present
812        py_executable_version = '%s.%s' % (
813            sys.version_info[0], sys.version_info[1])
814        if not py_executable.endswith(py_executable_version):
815            # symlinking pythonX.Y > python
816            pth = py_executable + '%s.%s' % (
817                    sys.version_info[0], sys.version_info[1])
818            if os.path.exists(pth):
819                os.unlink(pth)
820            os.symlink('python', pth)
821        else:
822            # reverse symlinking python -> pythonX.Y (with --python)
823            pth = join(bin_dir, 'python')
824            if os.path.exists(pth):
825                os.unlink(pth)
826            os.symlink(os.path.basename(py_executable), pth)
827
828    if sys.platform == 'win32' and ' ' in py_executable:
829        # There's a bug with subprocess on Windows when using a first
830        # argument that has a space in it.  Instead we have to quote
831        # the value:
832        py_executable = '"%s"' % py_executable
833    cmd = [py_executable, '-c', 'import sys; print sys.prefix']
834    logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
835    proc = subprocess.Popen(cmd,
836                            stdout=subprocess.PIPE)
837    proc_stdout, proc_stderr = proc.communicate()
838    proc_stdout = os.path.normcase(os.path.abspath(proc_stdout.strip()))
839    if proc_stdout != os.path.normcase(os.path.abspath(home_dir)):
840        logger.fatal(
841            'ERROR: The executable %s is not functioning' % py_executable)
842        logger.fatal(
843            'ERROR: It thinks sys.prefix is %r (should be %r)'
844            % (proc_stdout, os.path.normcase(os.path.abspath(home_dir))))
845        logger.fatal(
846            'ERROR: virtualenv is not compatible with this system or executable')
847        if sys.platform == 'win32':
848            logger.fatal(
849                '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)')
850        sys.exit(100)
851    else:
852        logger.info('Got sys.prefix result: %r' % proc_stdout)
853
854    pydistutils = os.path.expanduser('~/.pydistutils.cfg')
855    if os.path.exists(pydistutils):
856        logger.notify('Please make sure you remove any previous custom paths from '
857                      'your %s file.' % pydistutils)
858    # pyutilib.virtualenv: ignoring comment
859    return py_executable
860
861def install_activate(home_dir, bin_dir):
862    if sys.platform == 'win32' or is_jython and os._name == 'nt':
863        files = {'activate.bat': ACTIVATE_BAT,
864                 'deactivate.bat': DEACTIVATE_BAT}
865        if os.environ.get('OS') == 'Windows_NT' and os.environ.get('OSTYPE') == 'cygwin':
866            files['activate'] = ACTIVATE_SH
867    else:
868        files = {'activate': ACTIVATE_SH}
869    files['activate_this.py'] = ACTIVATE_THIS
870    for name, content in files.items():
871        content = content.replace('__VIRTUAL_ENV__', os.path.abspath(home_dir))
872        content = content.replace('__VIRTUAL_NAME__', os.path.basename(os.path.abspath(home_dir)))
873        content = content.replace('__BIN_NAME__', os.path.basename(bin_dir))
874        writefile(os.path.join(bin_dir, name), content)
875
876def install_distutils(lib_dir, home_dir):
877    distutils_path = os.path.join(lib_dir, 'distutils')
878    mkdir(distutils_path)
879    # pyutilib.virtualenv: ignoring comment
880    ## there's a local distutils.cfg with a prefix setting?
881    home_dir = os.path.abspath(home_dir)
882    # pyutilib.virtualenv: ignoring comment
883    #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir
884    writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT)
885    writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False)
886
887def fix_lib64(lib_dir):
888    """
889    Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y
890    instead of lib/pythonX.Y.  If this is such a platform we'll just create a
891    symlink so lib64 points to lib
892    """
893    if [p for p in distutils.sysconfig.get_config_vars().values()
894        if isinstance(p, basestring) and 'lib64' in p]:
895        logger.debug('This system uses lib64; symlinking lib64 to lib')
896        assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], (
897            "Unexpected python lib dir: %r" % lib_dir)
898        lib_parent = os.path.dirname(lib_dir)
899        assert os.path.basename(lib_parent) == 'lib', (
900            "Unexpected parent dir: %r" % lib_parent)
901        copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64'))
902
903def resolve_interpreter(exe):
904    """
905    If the executable given isn't an absolute path, search $PATH for the interpreter
906    """
907    if os.path.abspath(exe) != exe:
908        paths = os.environ.get('PATH', '').split(os.pathsep)
909        for path in paths:
910            if os.path.exists(os.path.join(path, exe)):
911                exe = os.path.join(path, exe)
912                break
913    if not os.path.exists(exe):
914        logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
915        sys.exit(3)
916    return exe
917
918############################################################
919## Relocating the environment:
920
921def make_environment_relocatable(home_dir):
922    """
923    Makes the already-existing environment use relative paths, and takes out
924    the #!-based environment selection in scripts.
925    """
926    activate_this = os.path.join(home_dir, 'bin', 'activate_this.py')
927    if not os.path.exists(activate_this):
928        logger.fatal(
929            'The environment doesn\'t have a file %s -- please re-run virtualenv '
930            'on this environment to update it' % activate_this)
931    fixup_scripts(home_dir)
932    fixup_pth_and_egg_link(home_dir)
933    # pyutilib.virtualenv: ignoring comment
934
935OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3],
936                  'activate', 'activate.bat', 'activate_this.py']
937
938def fixup_scripts(home_dir):
939    # This is what we expect at the top of scripts:
940    shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir))
941    # This is what we'll put:
942    new_shebang = '#!/usr/bin/env python%s' % sys.version[:3]
943    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"
944    bin_dir = os.path.join(home_dir, 'bin')
945    for filename in os.listdir(bin_dir):
946        filename = os.path.join(bin_dir, filename)
947        if not os.path.isfile(filename):
948            # ignore subdirs, e.g. .svn ones.
949            continue
950        f = open(filename, 'rb')
951        lines = f.readlines()
952        f.close()
953        if not lines:
954            logger.warn('Script %s is an empty file' % filename)
955            continue
956        if not lines[0].strip().startswith(shebang):
957            if os.path.basename(filename) in OK_ABS_SCRIPTS:
958                logger.debug('Cannot make script %s relative' % filename)
959            elif lines[0].strip() == new_shebang:
960                logger.info('Script %s has already been made relative' % filename)
961            else:
962                logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)'
963                            % (filename, shebang))
964            continue
965        logger.notify('Making script %s relative' % filename)
966        lines = [new_shebang+'\n', activate+'\n'] + lines[1:]
967        f = open(filename, 'wb')
968        f.writelines(lines)
969        f.close()
970
971def fixup_pth_and_egg_link(home_dir, sys_path=None):
972    """Makes .pth and .egg-link files use relative paths"""
973    home_dir = os.path.normcase(os.path.abspath(home_dir))
974    if sys_path is None:
975        sys_path = sys.path
976    for path in sys_path:
977        if not path:
978            path = '.'
979        if not os.path.isdir(path):
980            continue
981        path = os.path.normcase(os.path.abspath(path))
982        if not path.startswith(home_dir):
983            logger.debug('Skipping system (non-environment) directory %s' % path)
984            continue
985        for filename in os.listdir(path):
986            filename = os.path.join(path, filename)
987            if filename.endswith('.pth'):
988                if not os.access(filename, os.W_OK):
989                    logger.warn('Cannot write .pth file %s, skipping' % filename)
990                else:
991                    fixup_pth_file(filename)
992            if filename.endswith('.egg-link'):
993                if not os.access(filename, os.W_OK):
994                    logger.warn('Cannot write .egg-link file %s, skipping' % filename)
995                else:
996                    fixup_egg_link(filename)
997
998def fixup_pth_file(filename):
999    lines = []
1000    prev_lines = []
1001    f = open(filename)
1002    prev_lines = f.readlines()
1003    f.close()
1004    for line in prev_lines:
1005        line = line.strip()
1006        if (not line or line.startswith('#') or line.startswith('import ')
1007            or os.path.abspath(line) != line):
1008            lines.append(line)
1009        else:
1010            new_value = make_relative_path(filename, line)
1011            if line != new_value:
1012                logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
1013            lines.append(new_value)
1014    if lines == prev_lines:
1015        logger.info('No changes to .pth file %s' % filename)
1016        return
1017    logger.notify('Making paths in .pth file %s relative' % filename)
1018    f = open(filename, 'w')
1019    f.write('\n'.join(lines) + '\n')
1020    f.close()
1021
1022def fixup_egg_link(filename):
1023    f = open(filename)
1024    link = f.read().strip()
1025    f.close()
1026    if os.path.abspath(link) != link:
1027        logger.debug('Link in %s already relative' % filename)
1028        return
1029    new_link = make_relative_path(filename, link)
1030    logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
1031    f = open(filename, 'w')
1032    f.write(new_link)
1033    f.close()
1034
1035def make_relative_path(source, dest, dest_is_directory=True):
1036    """
1037    Make a filename relative, where the filename is dest, and it is
1038    being referred to from the filename source.
1039
1040        >>> make_relative_path('/usr/share/something/a-file.pth',
1041        ...                    '/usr/share/another-place/src/Directory')
1042        '../another-place/src/Directory'
1043        >>> make_relative_path('/usr/share/something/a-file.pth',
1044        ...                    '/home/user/src/Directory')
1045        '../../../home/user/src/Directory'
1046        >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/')
1047        './'
1048    """
1049    source = os.path.dirname(source)
1050    if not dest_is_directory:
1051        dest_filename = os.path.basename(dest)
1052        dest = os.path.dirname(dest)
1053    dest = os.path.normpath(os.path.abspath(dest))
1054    source = os.path.normpath(os.path.abspath(source))
1055    dest_parts = dest.strip(os.path.sep).split(os.path.sep)
1056    source_parts = source.strip(os.path.sep).split(os.path.sep)
1057    while dest_parts and source_parts and dest_parts[0] == source_parts[0]:
1058        dest_parts.pop(0)
1059        source_parts.pop(0)
1060    full_parts = ['..']*len(source_parts) + dest_parts
1061    if not dest_is_directory:
1062        full_parts.append(dest_filename)
1063    if not full_parts:
1064        # Special case for the current directory (otherwise it'd be '')
1065        return './'
1066    return os.path.sep.join(full_parts)
1067
1068
1069
1070############################################################
1071## Bootstrap script creation:
1072
1073def create_bootstrap_script(extra_text, python_version=''):
1074    """
1075    Creates a bootstrap script, which is like this script but with
1076    extend_parser, adjust_options, and after_install hooks.
1077
1078    This returns a string that (written to disk of course) can be used
1079    as a bootstrap script with your own customizations.  The script
1080    will be the standard virtualenv.py script, with your extra text
1081    added (your extra text should be Python code).
1082
1083    If you include these functions, they will be called:
1084
1085    ``extend_parser(optparse_parser)``:
1086        You can add or remove options from the parser here.
1087
1088    ``adjust_options(options, args)``:
1089        You can change options here, or change the args (if you accept
1090        different kinds of arguments, be sure you modify ``args`` so it is
1091        only ``[DEST_DIR]``).
1092
1093    ``after_install(options, home_dir)``:
1094
1095        After everything is installed, this function is called.  This
1096        is probably the function you are most likely to use.  An
1097        example would be::
1098
1099            def after_install(options, home_dir):
1100                subprocess.call([join(home_dir, 'bin', 'easy_install'),
1101                                 'MyPackage'])
1102                subprocess.call([join(home_dir, 'bin', 'my-package-script'),
1103                                 'setup', home_dir])
1104
1105        This example immediately installs a package, and runs a setup
1106        script from that package.
1107
1108    If you provide something like ``python_version='2.4'`` then the
1109    script will start with ``#!/usr/bin/env python2.4`` instead of
1110    ``#!/usr/bin/env python``.  You can use this when the script must
1111    be run with a particular Python version.
1112    """
1113    filename = __file__
1114    if filename.endswith('.pyc'):
1115        filename = filename[:-1]
1116    f = open(filename, 'rb')
1117    content = f.read()
1118    f.close()
1119    py_exe = 'python%s' % python_version
1120    content = (('#!/usr/bin/env %s\n' % py_exe)
1121               + '## WARNING: This file is generated\n'
1122               + content)
1123    return content.replace('##EXT' 'END##', extra_text)
1124
1125
1126#
1127# Imported from odict.py
1128#
1129
1130# odict.py
1131# An Ordered Dictionary object
1132# Copyright (C) 2005 Nicola Larosa, Michael Foord
1133# E-mail: nico AT tekNico DOT net, fuzzyman AT voidspace DOT org DOT uk
1134
1135# This software is licensed under the terms of the BSD license.
1136# http://www.voidspace.org.uk/python/license.shtml
1137# Basically you're free to copy, modify, distribute and relicense it,
1138# So long as you keep a copy of the license with it.
1139
1140# Documentation at http://www.voidspace.org.uk/python/odict.html
1141# For information about bugfixes, updates and support, please join the
1142# Pythonutils mailing list:
1143# http://groups.google.com/group/pythonutils/
1144# Comments, suggestions and bug reports welcome.
1145
1146"""A dict that keeps keys in insertion order"""
1147#from __future__ import generators
1148
1149__author__ = ('Nicola Larosa <nico-NoSp@m-tekNico.net>,'
1150    'Michael Foord <fuzzyman AT voidspace DOT org DOT uk>')
1151
1152__docformat__ = "restructuredtext en"
1153
1154__revision__ = '$Id: odict.py 129 2005-09-12 18:15:28Z teknico $'
1155
1156__version__ = '0.2.2'
1157
1158__all__ = ['OrderedDict', 'SequenceOrderedDict']
1159
1160import sys
1161INTP_VER = sys.version_info[:2]
1162if INTP_VER < (2, 2):
1163    raise RuntimeError("Python v.2.2 or later required")
1164
1165import types, warnings
1166
1167class OrderedDict(dict):
1168    """
1169    A class of dictionary that keeps the insertion order of keys.
1170   
1171    All appropriate methods return keys, items, or values in an ordered way.
1172   
1173    All normal dictionary methods are available. Update and comparison is
1174    restricted to other OrderedDict objects.
1175   
1176    Various sequence methods are available, including the ability to explicitly
1177    mutate the key ordering.
1178   
1179    __contains__ tests:
1180   
1181    >>> d = OrderedDict(((1, 3),))
1182    >>> 1 in d
1183    1
1184    >>> 4 in d
1185    0
1186   
1187    __getitem__ tests:
1188   
1189    >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[2]
1190    1
1191    >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[4]
1192    Traceback (most recent call last):
1193    KeyError: 4
1194   
1195    __len__ tests:
1196   
1197    >>> len(OrderedDict())
1198    0
1199    >>> len(OrderedDict(((1, 3), (3, 2), (2, 1))))
1200    3
1201   
1202    get tests:
1203   
1204    >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1205    >>> d.get(1)
1206    3
1207    >>> d.get(4) is None
1208    1
1209    >>> d.get(4, 5)
1210    5
1211    >>> d
1212    OrderedDict([(1, 3), (3, 2), (2, 1)])
1213   
1214    has_key tests:
1215   
1216    >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1217    >>> d.has_key(1)
1218    1
1219    >>> d.has_key(4)
1220    0
1221    """
1222
1223    def __init__(self, init_val=(), strict=False):
1224        """
1225        Create a new ordered dictionary. Cannot init from a normal dict,
1226        nor from kwargs, since items order is undefined in those cases.
1227       
1228        If the ``strict`` keyword argument is ``True`` (``False`` is the
1229        default) then when doing slice assignment - the ``OrderedDict`` you are
1230        assigning from *must not* contain any keys in the remaining dict.
1231       
1232        >>> OrderedDict()
1233        OrderedDict([])
1234        >>> OrderedDict({1: 1})
1235        Traceback (most recent call last):
1236        TypeError: undefined order, cannot get items from dict
1237        >>> OrderedDict({1: 1}.items())
1238        OrderedDict([(1, 1)])
1239        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1240        >>> d
1241        OrderedDict([(1, 3), (3, 2), (2, 1)])
1242        >>> OrderedDict(d)
1243        OrderedDict([(1, 3), (3, 2), (2, 1)])
1244        """
1245        self.strict = strict
1246        dict.__init__(self)
1247        if isinstance(init_val, OrderedDict):
1248            self._sequence = init_val.keys()
1249            dict.update(self, init_val)
1250        elif isinstance(init_val, dict):
1251            # we lose compatibility with other ordered dict types this way
1252            raise TypeError('undefined order, cannot get items from dict')
1253        else:
1254            self._sequence = []
1255            self.update(init_val)
1256
1257### Special methods ###
1258
1259    def __delitem__(self, key):
1260        """
1261        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1262        >>> del d[3]
1263        >>> d
1264        OrderedDict([(1, 3), (2, 1)])
1265        >>> del d[3]
1266        Traceback (most recent call last):
1267        KeyError: 3
1268        >>> d[3] = 2
1269        >>> d
1270        OrderedDict([(1, 3), (2, 1), (3, 2)])
1271        >>> del d[0:1]
1272        >>> d
1273        OrderedDict([(2, 1), (3, 2)])
1274        """
1275        if isinstance(key, types.SliceType):
1276            # NOTE: efficiency?
1277            keys = self._sequence[key]
1278            for entry in keys:
1279                dict.__delitem__(self, entry)
1280            del self._sequence[key]
1281        else:
1282            # do the dict.__delitem__ *first* as it raises
1283            # the more appropriate error
1284            dict.__delitem__(self, key)
1285            self._sequence.remove(key)
1286
1287    def __eq__(self, other):
1288        """
1289        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1290        >>> d == OrderedDict(d)
1291        True
1292        >>> d == OrderedDict(((1, 3), (2, 1), (3, 2)))
1293        False
1294        >>> d == OrderedDict(((1, 0), (3, 2), (2, 1)))
1295        False
1296        >>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
1297        False
1298        >>> d == dict(d)
1299        False
1300        >>> d == False
1301        False
1302        """
1303        if isinstance(other, OrderedDict):
1304            # NOTE: efficiency?
1305            #   Generate both item lists for each compare
1306            return (self.items() == other.items())
1307        else:
1308            return False
1309
1310    def __lt__(self, other):
1311        """
1312        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1313        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
1314        >>> c < d
1315        True
1316        >>> d < c
1317        False
1318        >>> d < dict(c)
1319        Traceback (most recent call last):
1320        TypeError: Can only compare with other OrderedDicts
1321        """
1322        if not isinstance(other, OrderedDict):
1323            raise TypeError('Can only compare with other OrderedDicts')
1324        # NOTE: efficiency?
1325        #   Generate both item lists for each compare
1326        return (self.items() < other.items())
1327
1328    def __le__(self, other):
1329        """
1330        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1331        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
1332        >>> e = OrderedDict(d)
1333        >>> c <= d
1334        True
1335        >>> d <= c
1336        False
1337        >>> d <= dict(c)
1338        Traceback (most recent call last):
1339        TypeError: Can only compare with other OrderedDicts
1340        >>> d <= e
1341        True
1342        """
1343        if not isinstance(other, OrderedDict):
1344            raise TypeError('Can only compare with other OrderedDicts')
1345        # NOTE: efficiency?
1346        #   Generate both item lists for each compare
1347        return (self.items() <= other.items())
1348
1349    def __ne__(self, other):
1350        """
1351        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1352        >>> d != OrderedDict(d)
1353        False
1354        >>> d != OrderedDict(((1, 3), (2, 1), (3, 2)))
1355        True
1356        >>> d != OrderedDict(((1, 0), (3, 2), (2, 1)))
1357        True
1358        >>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
1359        False
1360        >>> d != dict(d)
1361        True
1362        >>> d != False
1363        True
1364        """
1365        if isinstance(other, OrderedDict):
1366            # NOTE: efficiency?
1367            #   Generate both item lists for each compare
1368            return not (self.items() == other.items())
1369        else:
1370            return True
1371
1372    def __gt__(self, other):
1373        """
1374        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1375        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
1376        >>> d > c
1377        True
1378        >>> c > d
1379        False
1380        >>> d > dict(c)
1381        Traceback (most recent call last):
1382        TypeError: Can only compare with other OrderedDicts
1383        """
1384        if not isinstance(other, OrderedDict):
1385            raise TypeError('Can only compare with other OrderedDicts')
1386        # NOTE: efficiency?
1387        #   Generate both item lists for each compare
1388        return (self.items() > other.items())
1389
1390    def __ge__(self, other):
1391        """
1392        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1393        >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
1394        >>> e = OrderedDict(d)
1395        >>> c >= d
1396        False
1397        >>> d >= c
1398        True
1399        >>> d >= dict(c)
1400        Traceback (most recent call last):
1401        TypeError: Can only compare with other OrderedDicts
1402        >>> e >= d
1403        True
1404        """
1405        if not isinstance(other, OrderedDict):
1406            raise TypeError('Can only compare with other OrderedDicts')
1407        # NOTE: efficiency?
1408        #   Generate both item lists for each compare
1409        return (self.items() >= other.items())
1410
1411    def __repr__(self):
1412        """
1413        Used for __repr__ and __str__
1414       
1415        >>> r1 = repr(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
1416        >>> r1
1417        "OrderedDict([('a', 'b'), ('c', 'd'), ('e', 'f')])"
1418        >>> r2 = repr(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
1419        >>> r2
1420        "OrderedDict([('a', 'b'), ('e', 'f'), ('c', 'd')])"
1421        >>> r1 == str(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
1422        True
1423        >>> r2 == str(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
1424        True
1425        """
1426        return '%s([%s])' % (self.__class__.__name__, ', '.join(
1427            ['(%r, %r)' % (key, self[key]) for key in self._sequence]))
1428
1429    def __setitem__(self, key, val):
1430        """
1431        Allows slice assignment, so long as the slice is an OrderedDict
1432        >>> d = OrderedDict()
1433        >>> d['a'] = 'b'
1434        >>> d['b'] = 'a'
1435        >>> d[3] = 12
1436        >>> d
1437        OrderedDict([('a', 'b'), ('b', 'a'), (3, 12)])
1438        >>> d[:] = OrderedDict(((1, 2), (2, 3), (3, 4)))
1439        >>> d
1440        OrderedDict([(1, 2), (2, 3), (3, 4)])
1441        >>> d[::2] = OrderedDict(((7, 8), (9, 10)))
1442        >>> d
1443        OrderedDict([(7, 8), (2, 3), (9, 10)])
1444        >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)))
1445        >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
1446        >>> d
1447        OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
1448        >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)), strict=True)
1449        >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
1450        >>> d
1451        OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
1452       
1453        >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)), strict=True)
1454        >>> a[3] = 4
1455        >>> a
1456        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1457        >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1458        >>> a
1459        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1460        >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)])
1461        Traceback (most recent call last):
1462        ValueError: slice assignment must be from unique keys
1463        >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)))
1464        >>> a[3] = 4
1465        >>> a
1466        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1467        >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1468        >>> a
1469        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1470        >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1471        >>> a
1472        OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1473        >>> a[::-1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1474        >>> a
1475        OrderedDict([(3, 4), (2, 3), (1, 2), (0, 1)])
1476       
1477        >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1478        >>> d[:1] = 3
1479        Traceback (most recent call last):
1480        TypeError: slice assignment requires an OrderedDict
1481       
1482        >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
1483        >>> d[:1] = OrderedDict([(9, 8)])
1484        >>> d
1485        OrderedDict([(9, 8), (1, 2), (2, 3), (3, 4)])
1486        """
1487        if isinstance(key, types.SliceType):
1488            if not isinstance(val, OrderedDict):
1489                # NOTE: allow a list of tuples?
1490                raise TypeError('slice assignment requires an OrderedDict')
1491            keys = self._sequence[key]
1492            # NOTE: Could use ``range(*key.indices(len(self._sequence)))``
1493            indexes = range(len(self._sequence))[key]
1494            if key.step is None:
1495                # NOTE: new slice may not be the same size as the one being
1496                #   overwritten !
1497                # NOTE: What is the algorithm for an impossible slice?
1498                #   e.g. d[5:3]
1499                pos = key.start or 0
1500                del self[key]
1501                newkeys = val.keys()
1502                for k in newkeys:
1503                    if k in self:
1504                        if self.strict:
1505                            raise ValueError('slice assignment must be from '
1506                                'unique keys')
1507                        else:
1508                            # NOTE: This removes duplicate keys *first*
1509                            #   so start position might have changed?
1510                            del self[k]
1511                self._sequence = (self._sequence[:pos] + newkeys +
1512                    self._sequence[pos:])
1513                dict.update(self, val)
1514            else:
1515                # extended slice - length of new slice must be the same
1516                # as the one being replaced
1517                if len(keys) != len(val):
1518                    raise ValueError('attempt to assign sequence of size %s '
1519                        'to extended slice of size %s' % (len(val), len(keys)))
1520                # NOTE: efficiency?
1521                del self[key]
1522                item_list = zip(indexes, val.items())
1523                # smallest indexes first - higher indexes not guaranteed to
1524                # exist
1525                item_list.sort()
1526                for pos, (newkey, newval) in item_list:
1527                    if self.strict and newkey in self:
1528                        raise ValueError('slice assignment must be from unique'
1529                            ' keys')
1530                    self.insert(pos, newkey, newval)
1531        else:
1532            if key not in self:
1533                self._sequence.append(key)
1534            dict.__setitem__(self, key, val)
1535
1536    def __getitem__(self, key):
1537        """
1538        Allows slicing. Returns an OrderedDict if you slice.
1539        >>> b = OrderedDict([(7, 0), (6, 1), (5, 2), (4, 3), (3, 4), (2, 5), (1, 6)])
1540        >>> b[::-1]
1541        OrderedDict([(1, 6), (2, 5), (3, 4), (4, 3), (5, 2), (6, 1), (7, 0)])
1542        >>> b[2:5]
1543        OrderedDict([(5, 2), (4, 3), (3, 4)])
1544        >>> type(b[2:4])
1545        <class '__main__.OrderedDict'>
1546        """
1547        if isinstance(key, types.SliceType):
1548            # NOTE: does this raise the error we want?
1549            keys = self._sequence[key]
1550            # NOTE: efficiency?
1551            return OrderedDict([(entry, self[entry]) for entry in keys])
1552        else:
1553            return dict.__getitem__(self, key)
1554
1555    __str__ = __repr__
1556
1557    def __setattr__(self, name, value):
1558        """
1559        Implemented so that accesses to ``sequence`` raise a warning and are
1560        diverted to the new ``setkeys`` method.
1561        """
1562        if name == 'sequence':
1563            warnings.warn('Use of the sequence attribute is deprecated.'
1564                ' Use the keys method instead.', DeprecationWarning)
1565            # NOTE: doesn't return anything
1566            self.setkeys(value)
1567        else:
1568            # NOTE: do we want to allow arbitrary setting of attributes?
1569            #   Or do we want to manage it?
1570            object.__setattr__(self, name, value)
1571
1572    def __getattr__(self, name):
1573        """
1574        Implemented so that access to ``sequence`` raises a warning.
1575       
1576        >>> d = OrderedDict()
1577        >>> d.sequence
1578        []
1579        """
1580        if name == 'sequence':
1581            warnings.warn('Use of the sequence attribute is deprecated.'
1582                ' Use the keys method instead.', DeprecationWarning)
1583            # NOTE: Still (currently) returns a direct reference. Need to
1584            #   because code that uses sequence will expect to be able to
1585            #   mutate it in place.
1586            return self._sequence
1587        else:
1588            # raise the appropriate error
1589            raise AttributeError("OrderedDict has no '%s' attribute" % name)
1590
1591    def __deepcopy__(self, memo):
1592        """
1593        To allow deepcopy to work with OrderedDict.
1594       
1595        >>> from copy import deepcopy
1596        >>> a = OrderedDict([(1, 1), (2, 2), (3, 3)])
1597        >>> a['test'] = {}
1598        >>> b = deepcopy(a)
1599        >>> b == a
1600        True
1601        >>> b is a
1602        False
1603        >>> a['test'] is b['test']
1604        False
1605        """
1606        from copy import deepcopy
1607        return self.__class__(deepcopy(self.items(), memo), self.strict)
1608
1609
1610### Read-only methods ###
1611
1612    def copy(self):
1613        """
1614        >>> OrderedDict(((1, 3), (3, 2), (2, 1))).copy()
1615        OrderedDict([(1, 3), (3, 2), (2, 1)])
1616        """
1617        return OrderedDict(self)
1618
1619    def items(self):
1620        """
1621        ``items`` returns a list of tuples representing all the
1622        ``(key, value)`` pairs in the dictionary.
1623       
1624        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1625        >>> d.items()
1626        [(1, 3), (3, 2), (2, 1)]
1627        >>> d.clear()
1628        >>> d.items()
1629        []
1630        """
1631        return zip(self._sequence, self.values())
1632
1633    def keys(self):
1634        """
1635        Return a list of keys in the ``OrderedDict``.
1636       
1637        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1638        >>> d.keys()
1639        [1, 3, 2]
1640        """
1641        return self._sequence[:]
1642
1643    def values(self, values=None):
1644        """
1645        Return a list of all the values in the OrderedDict.
1646       
1647        Optionally you can pass in a list of values, which will replace the
1648        current list. The value list must be the same len as the OrderedDict.
1649       
1650        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1651        >>> d.values()
1652        [3, 2, 1]
1653        """
1654        return [self[key] for key in self._sequence]
1655
1656    def iteritems(self):
1657        """
1658        >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iteritems()
1659        >>> ii.next()
1660        (1, 3)
1661        >>> ii.next()
1662        (3, 2)
1663        >>> ii.next()
1664        (2, 1)
1665        >>> ii.next()
1666        Traceback (most recent call last):
1667        StopIteration
1668        """
1669        def make_iter(self=self):
1670            keys = self.iterkeys()
1671            while True:
1672                key = keys.next()
1673                yield (key, self[key])
1674        return make_iter()
1675
1676    def iterkeys(self):
1677        """
1678        >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iterkeys()
1679        >>> ii.next()
1680        1
1681        >>> ii.next()
1682        3
1683        >>> ii.next()
1684        2
1685        >>> ii.next()
1686        Traceback (most recent call last):
1687        StopIteration
1688        """
1689        return iter(self._sequence)
1690
1691    __iter__ = iterkeys
1692
1693    def itervalues(self):
1694        """
1695        >>> iv = OrderedDict(((1, 3), (3, 2), (2, 1))).itervalues()
1696        >>> iv.next()
1697        3
1698        >>> iv.next()
1699        2
1700        >>> iv.next()
1701        1
1702        >>> iv.next()
1703        Traceback (most recent call last):
1704        StopIteration
1705        """
1706        def make_iter(self=self):
1707            keys = self.iterkeys()
1708            while True:
1709                yield self[keys.next()]
1710        return make_iter()
1711
1712### Read-write methods ###
1713
1714    def clear(self):
1715        """
1716        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1717        >>> d.clear()
1718        >>> d
1719        OrderedDict([])
1720        """
1721        dict.clear(self)
1722        self._sequence = []
1723
1724    def pop(self, key, *args):
1725        """
1726        No dict.pop in Python 2.2, gotta reimplement it
1727       
1728        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1729        >>> d.pop(3)
1730        2
1731        >>> d
1732        OrderedDict([(1, 3), (2, 1)])
1733        >>> d.pop(4)
1734        Traceback (most recent call last):
1735        KeyError: 4
1736        >>> d.pop(4, 0)
1737        0
1738        >>> d.pop(4, 0, 1)
1739        Traceback (most recent call last):
1740        TypeError: pop expected at most 2 arguments, got 3
1741        """
1742        if len(args) > 1:
1743            raise TypeError, ('pop expected at most 2 arguments, got %s' %
1744                (len(args) + 1))
1745        if key in self:
1746            val = self[key]
1747            del self[key]
1748        else:
1749            try:
1750                val = args[0]
1751            except IndexError:
1752                raise KeyError(key)
1753        return val
1754
1755    def popitem(self, i=-1):
1756        """
1757        Delete and return an item specified by index, not a random one as in
1758        dict. The index is -1 by default (the last item).
1759       
1760        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1761        >>> d.popitem()
1762        (2, 1)
1763        >>> d
1764        OrderedDict([(1, 3), (3, 2)])
1765        >>> d.popitem(0)
1766        (1, 3)
1767        >>> OrderedDict().popitem()
1768        Traceback (most recent call last):
1769        KeyError: 'popitem(): dictionary is empty'
1770        >>> d.popitem(2)
1771        Traceback (most recent call last):
1772        IndexError: popitem(): index 2 not valid
1773        """
1774        if not self._sequence:
1775            raise KeyError('popitem(): dictionary is empty')
1776        try:
1777            key = self._sequence[i]
1778        except IndexError:
1779            raise IndexError('popitem(): index %s not valid' % i)
1780        return (key, self.pop(key))
1781
1782    def setdefault(self, key, defval = None):
1783        """
1784        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1785        >>> d.setdefault(1)
1786        3
1787        >>> d.setdefault(4) is None
1788        True
1789        >>> d
1790        OrderedDict([(1, 3), (3, 2), (2, 1), (4, None)])
1791        >>> d.setdefault(5, 0)
1792        0
1793        >>> d
1794        OrderedDict([(1, 3), (3, 2), (2, 1), (4, None), (5, 0)])
1795        """
1796        if key in self:
1797            return self[key]
1798        else:
1799            self[key] = defval
1800            return defval
1801
1802    def update(self, from_od):
1803        """
1804        Update from another OrderedDict or sequence of (key, value) pairs
1805       
1806        >>> d = OrderedDict(((1, 0), (0, 1)))
1807        >>> d.update(OrderedDict(((1, 3), (3, 2), (2, 1))))
1808        >>> d
1809        OrderedDict([(1, 3), (0, 1), (3, 2), (2, 1)])
1810        >>> d.update({4: 4})
1811        Traceback (most recent call last):
1812        TypeError: undefined order, cannot get items from dict
1813        >>> d.update((4, 4))
1814        Traceback (most recent call last):
1815        TypeError: cannot convert dictionary update sequence element "4" to a 2-item sequence
1816        """
1817        if isinstance(from_od, OrderedDict):
1818            for key, val in from_od.items():
1819                self[key] = val
1820        elif isinstance(from_od, dict):
1821            # we lose compatibility with other ordered dict types this way
1822            raise TypeError('undefined order, cannot get items from dict')
1823        else:
1824            # NOTE: efficiency?
1825            # sequence of 2-item sequences, or error
1826            for item in from_od:
1827                try:
1828                    key, val = item
1829                except TypeError:
1830                    raise TypeError('cannot convert dictionary update'
1831                        ' sequence element "%s" to a 2-item sequence' % item)
1832                self[key] = val
1833
1834    def rename(self, old_key, new_key):
1835        """
1836        Rename the key for a given value, without modifying sequence order.
1837       
1838        For the case where new_key already exists this raise an exception,
1839        since if new_key exists, it is ambiguous as to what happens to the
1840        associated values, and the position of new_key in the sequence.
1841       
1842        >>> od = OrderedDict()
1843        >>> od['a'] = 1
1844        >>> od['b'] = 2
1845        >>> od.items()
1846        [('a', 1), ('b', 2)]
1847        >>> od.rename('b', 'c')
1848        >>> od.items()
1849        [('a', 1), ('c', 2)]
1850        >>> od.rename('c', 'a')
1851        Traceback (most recent call last):
1852        ValueError: New key already exists: 'a'
1853        >>> od.rename('d', 'b')
1854        Traceback (most recent call last):
1855        KeyError: 'd'
1856        """
1857        if new_key == old_key:
1858            # no-op
1859            return
1860        if new_key in self:
1861            raise ValueError("New key already exists: %r" % new_key)
1862        # rename sequence entry
1863        value = self[old_key] 
1864        old_idx = self._sequence.index(old_key)
1865        self._sequence[old_idx] = new_key
1866        # rename internal dict entry
1867        dict.__delitem__(self, old_key)
1868        dict.__setitem__(self, new_key, value)
1869
1870    def setitems(self, items):
1871        """
1872        This method allows you to set the items in the dict.
1873       
1874        It takes a list of tuples - of the same sort returned by the ``items``
1875        method.
1876       
1877        >>> d = OrderedDict()
1878        >>> d.setitems(((3, 1), (2, 3), (1, 2)))
1879        >>> d
1880        OrderedDict([(3, 1), (2, 3), (1, 2)])
1881        """
1882        self.clear()
1883        # NOTE: this allows you to pass in an OrderedDict as well :-)
1884        self.update(items)
1885
1886    def setkeys(self, keys):
1887        """
1888        ``setkeys`` all ows you to pass in a new list of keys which will
1889        replace the current set. This must contain the same set of keys, but
1890        need not be in the same order.
1891       
1892        If you pass in new keys that don't match, a ``KeyError`` will be
1893        raised.
1894       
1895        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1896        >>> d.keys()
1897        [1, 3, 2]
1898        >>> d.setkeys((1, 2, 3))
1899        >>> d
1900        OrderedDict([(1, 3), (2, 1), (3, 2)])
1901        >>> d.setkeys(['a', 'b', 'c'])
1902        Traceback (most recent call last):
1903        KeyError: 'Keylist is not the same as current keylist.'
1904        """
1905        # NOTE: Efficiency? (use set for Python 2.4 :-)
1906        # NOTE: list(keys) rather than keys[:] because keys[:] returns
1907        #   a tuple, if keys is a tuple.
1908        kcopy = list(keys)
1909        kcopy.sort()
1910        self._sequence.sort()
1911        if kcopy != self._sequence:
1912            raise KeyError('Keylist is not the same as current keylist.')
1913        # NOTE: This makes the _sequence attribute a new object, instead
1914        #       of changing it in place.
1915        # NOTE: efficiency?
1916        self._sequence = list(keys)
1917
1918    def setvalues(self, values):
1919        """
1920        You can pass in a list of values, which will replace the
1921        current list. The value list must be the same len as the OrderedDict.
1922       
1923        (Or a ``ValueError`` is raised.)
1924       
1925        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1926        >>> d.setvalues((1, 2, 3))
1927        >>> d
1928        OrderedDict([(1, 1), (3, 2), (2, 3)])
1929        >>> d.setvalues([6])
1930        Traceback (most recent call last):
1931        ValueError: Value list is not the same length as the OrderedDict.
1932        """
1933        if len(values) != len(self):
1934            # NOTE: correct error to raise?
1935            raise ValueError('Value list is not the same length as the '
1936                'OrderedDict.')
1937        self.update(zip(self, values))
1938
1939### Sequence Methods ###
1940
1941    def index(self, key):
1942        """
1943        Return the position of the specified key in the OrderedDict.
1944       
1945        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1946        >>> d.index(3)
1947        1
1948        >>> d.index(4)
1949        Traceback (most recent call last):
1950        ValueError: list.index(x): x not in list
1951        """
1952        return self._sequence.index(key)
1953
1954    def insert(self, index, key, value):
1955        """
1956        Takes ``index``, ``key``, and ``value`` as arguments.
1957       
1958        Sets ``key`` to ``value``, so that ``key`` is at position ``index`` in
1959        the OrderedDict.
1960       
1961        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1962        >>> d.insert(0, 4, 0)
1963        >>> d
1964        OrderedDict([(4, 0), (1, 3), (3, 2), (2, 1)])
1965        >>> d.insert(0, 2, 1)
1966        >>> d
1967        OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2)])
1968        >>> d.insert(8, 8, 1)
1969        >>> d
1970        OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2), (8, 1)])
1971        """
1972        if key in self:
1973            # NOTE: efficiency?
1974            del self[key]
1975        self._sequence.insert(index, key)
1976        dict.__setitem__(self, key, value)
1977
1978    def reverse(self):
1979        """
1980        Reverse the order of the OrderedDict.
1981       
1982        >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
1983        >>> d.reverse()
1984        >>> d
1985        OrderedDict([(2, 1), (3, 2), (1, 3)])
1986        """
1987        self._sequence.reverse()
1988
1989    def sort(self, *args, **kwargs):
1990        """
1991        Sort the key order in the OrderedDict.
1992       
1993        This method takes the same arguments as the ``list.sort`` method on
1994        your version of Python.
1995       
1996        >>> d = OrderedDict(((4, 1), (2, 2), (3, 3), (1, 4)))
1997        >>> d.sort()
1998        >>> d
1999        OrderedDict([(1, 4), (2, 2), (3, 3), (4, 1)])
2000        """
2001        self._sequence.sort(*args, **kwargs)
2002
2003class Keys(object):
2004    # NOTE: should this object be a subclass of list?
2005    """
2006    Custom object for accessing the keys of an OrderedDict.
2007   
2008    Can be called like the normal ``OrderedDict.keys`` method, but also
2009    supports indexing and sequence methods.
2010    """
2011
2012    def __init__(self, main):
2013        self._main = main
2014
2015    def __call__(self):
2016        """Pretend to be the keys method."""
2017        return self._main._keys()
2018
2019    def __getitem__(self, index):
2020        """Fetch the key at position i."""
2021        # NOTE: this automatically supports slicing :-)
2022        return self._main._sequence[index]
2023
2024    def __setitem__(self, index, name):
2025        """
2026        You cannot assign to keys, but you can do slice assignment to re-order
2027        them.
2028       
2029        You can only do slice assignment if the new set of keys is a reordering
2030        of the original set.
2031        """
2032        if isinstance(index, types.SliceType):
2033            # NOTE: efficiency?
2034            # check length is the same
2035            indexes = range(len(self._main._sequence))[index]
2036            if len(indexes) != len(name):
2037                raise ValueError('attempt to assign sequence of size %s '
2038                    'to slice of size %s' % (len(name), len(indexes)))
2039            # check they are the same keys
2040            # NOTE: Use set
2041            old_keys = self._main._sequence[index]
2042            new_keys = list(name)
2043            old_keys.sort()
2044            new_keys.sort()
2045            if old_keys != new_keys:
2046                raise KeyError('Keylist is not the same as current keylist.')
2047            orig_vals = [self._main[k] for k in name]
2048            del self._main[index]
2049            vals = zip(indexes, name, orig_vals)
2050            vals.sort()
2051            for i, k, v in vals:
2052                if self._main.strict and k in self._main:
2053                    raise ValueError('slice assignment must be from '
2054                        'unique keys')
2055                self._main.insert(i, k, v)
2056        else:
2057            raise ValueError('Cannot assign to keys')
2058
2059    ### following methods pinched from UserList and adapted ###
2060    def __repr__(self): return repr(self._main._sequence)
2061
2062    # NOTE: do we need to check if we are comparing with another ``Keys``
2063    #   object? (like the __cast method of UserList)
2064    def __lt__(self, other): return self._main._sequence <  other
2065    def __le__(self, other): return self._main._sequence <= other
2066    def __eq__(self, other): return self._main._sequence == other
2067    def __ne__(self, other): return self._main._sequence != other
2068    def __gt__(self, other): return self._main._sequence >  other
2069    def __ge__(self, other): return self._main._sequence >= other
2070    # NOTE: do we need __cmp__ as well as rich comparisons?
2071    def __cmp__(self, other): return cmp(self._main._sequence, other)
2072
2073    def __contains__(self, item): return item in self._main._sequence
2074    def __len__(self): return len(self._main._sequence)
2075    def __iter__(self): return self._main.iterkeys()
2076    def count(self, item): return self._main._sequence.count(item)
2077    def index(self, item, *args): return self._main._sequence.index(item, *args)
2078    def reverse(self): self._main._sequence.reverse()
2079    def sort(self, *args, **kwds): self._main._sequence.sort(*args, **kwds)
2080    def __mul__(self, n): return self._main._sequence*n
2081    __rmul__ = __mul__
2082    def __add__(self, other): return self._main._sequence + other
2083    def __radd__(self, other): return other + self._main._sequence
2084
2085    ## following methods not implemented for keys ##
2086    def __delitem__(self, i): raise TypeError('Can\'t delete items from keys')
2087    def __iadd__(self, other): raise TypeError('Can\'t add in place to keys')
2088    def __imul__(self, n): raise TypeError('Can\'t multiply keys in place')
2089    def append(self, item): raise TypeError('Can\'t append items to keys')
2090    def insert(self, i, item): raise TypeError('Can\'t insert items into keys')
2091    def pop(self, i=-1): raise TypeError('Can\'t pop items from keys')
2092    def remove(self, item): raise TypeError('Can\'t remove items from keys')
2093    def extend(self, other): raise TypeError('Can\'t extend keys')
2094
2095class Items(object):
2096    """
2097    Custom object for accessing the items of an OrderedDict.
2098   
2099    Can be called like the normal ``OrderedDict.items`` method, but also
2100    supports indexing and sequence methods.
2101    """
2102
2103    def __init__(self, main):
2104        self._main = main
2105
2106    def __call__(self):
2107        """Pretend to be the items method."""
2108        return self._main._items()
2109
2110    def __getitem__(self, index):
2111        """Fetch the item at position i."""
2112        if isinstance(index, types.SliceType):
2113            # fetching a slice returns an OrderedDict
2114            return self._main[index].items()
2115        key = self._main._sequence[index]
2116        return (key, self._main[key])
2117
2118    def __setitem__(self, index, item):
2119        """Set item at position i to item."""
2120        if isinstance(index, types.SliceType):
2121            # NOTE: item must be an iterable (list of tuples)
2122            self._main[index] = OrderedDict(item)
2123        else:
2124            # NOTE: Does this raise a sensible error?
2125            orig = self._main.keys[index]
2126            key, value = item
2127            if self._main.strict and key in self and (key != orig):
2128                raise ValueError('slice assignment must be from '
2129                        'unique keys')
2130            # delete the current one
2131            del self._main[self._main._sequence[index]]
2132            self._main.insert(index, key, value)
2133
2134    def __delitem__(self, i):
2135        """Delete the item at position i."""
2136        key = self._main._sequence[i]
2137        if isinstance(i, types.SliceType):
2138            for k in key:
2139                # NOTE: efficiency?
2140                del self._main[k]
2141        else:
2142            del self._main[key]
2143
2144    ### following methods pinched from UserList and adapted ###
2145    def __repr__(self): return repr(self._main.items())
2146
2147    # NOTE: do we need to check if we are comparing with another ``Items``
2148    #   object? (like the __cast method of UserList)
2149    def __lt__(self, other): return self._main.items() <  other
2150    def __le__(self, other): return self._main.items() <= other
2151    def __eq__(self, other): return self._main.items() == other
2152    def __ne__(self, other): return self._main.items() != other
2153    def __gt__(self, other): return self._main.items() >  other
2154    def __ge__(self, other): return self._main.items() >= other
2155    def __cmp__(self, other): return cmp(self._main.items(), other)
2156
2157    def __contains__(self, item): return item in self._main.items()
2158    def __len__(self): return len(self._main._sequence) # easier :-)
2159    def __iter__(self): return self._main.iteritems()
2160    def count(self, item): return self._main.items().count(item)
2161    def index(self, item, *args): return self._main.items().index(item, *args)
2162    def reverse(self): self._main.reverse()
2163    def sort(self, *args, **kwds): self._main.sort(*args, **kwds)
2164    def __mul__(self, n): return self._main.items()*n
2165    __rmul__ = __mul__
2166    def __add__(self, other): return self._main.items() + other
2167    def __radd__(self, other): return other + self._main.items()
2168
2169    def append(self, item):
2170        """Add an item to the end."""
2171        # NOTE: this is only append if the key isn't already present
2172        key, value = item
2173        self._main[key] = value
2174
2175    def insert(self, i, item):
2176        key, value = item
2177        self._main.insert(i, key, value)
2178
2179    def pop(self, i=-1):
2180        key = self._main._sequence[i]
2181        return (key, self._main.pop(key))
2182
2183    def remove(self, item):
2184        key, value = item
2185        try:
2186            assert value == self._main[key]
2187        except (KeyError, AssertionError):
2188            raise ValueError('ValueError: list.remove(x): x not in list')
2189        else:
2190            del self._main[key]
2191
2192    def extend(self, other):
2193        # NOTE: is only a true extend if none of the keys already present
2194        for item in other:
2195            key, value = item
2196            self._main[key] = value
2197
2198    def __iadd__(self, other):
2199        self.extend(other)
2200
2201    ## following methods not implemented for items ##
2202
2203    def __imul__(self, n): raise TypeError('Can\'t multiply items in place')
2204
2205class Values(object):
2206    """
2207    Custom object for accessing the values of an OrderedDict.
2208   
2209    Can be called like the normal ``OrderedDict.values`` method, but also
2210    supports indexing and sequence methods.
2211    """
2212
2213    def __init__(self, main):
2214        self._main = main
2215
2216    def __call__(self):
2217        """Pretend to be the values method."""
2218        return self._main._values()
2219
2220    def __getitem__(self, index):
2221        """Fetch the value at position i."""
2222        if isinstance(index, types.SliceType):
2223            return [self._main[key] for key in self._main._sequence[index]]
2224        else:
2225            return self._main[self._main._sequence[index]]
2226
2227    def __setitem__(self, index, value):
2228        """
2229        Set the value at position i to value.
2230       
2231        You can only do slice assignment to values if you supply a sequence of
2232        equal length to the slice you are replacing.
2233        """
2234        if isinstance(index, types.SliceType):
2235            keys = self._main._sequence[index]
2236            if len(keys) != len(value):
2237                raise ValueError('attempt to assign sequence of size %s '
2238                    'to slice of size %s' % (len(name), len(keys)))
2239            # NOTE: efficiency?  Would be better to calculate the indexes
2240            #   directly from the slice object
2241            # NOTE: the new keys can collide with existing keys (or even
2242            #   contain duplicates) - these will overwrite
2243            for key, val in zip(keys, value):
2244                self._main[key] = val
2245        else:
2246            self._main[self._main._sequence[index]] = value
2247
2248    ### following methods pinched from UserList and adapted ###
2249    def __repr__(self): return repr(self._main.values())
2250
2251    # NOTE: do we need to check if we are comparing with another ``Values``
2252    #   object? (like the __cast method of UserList)
2253    def __lt__(self, other): return self._main.values() <  other
2254    def __le__(self, other): return self._main.values() <= other
2255    def __eq__(self, other): return self._main.values() == other
2256    def __ne__(self, other): return self._main.values() != other
2257    def __gt__(self, other): return self._main.values() >  other
2258    def __ge__(self, other): return self._main.values() >= other
2259    def __cmp__(self, other): return cmp(self._main.values(), other)
2260
2261    def __contains__(self, item): return item in self._main.values()
2262    def __len__(self): return len(self._main._sequence) # easier :-)
2263    def __iter__(self): return self._main.itervalues()
2264    def count(self, item): return self._main.values().count(item)
2265    def index(self, item, *args): return self._main.values().index(item, *args)
2266
2267    def reverse(self):
2268        """Reverse the values"""
2269        vals = self._main.values()
2270        vals.reverse()
2271        # NOTE: efficiency
2272        self[:] = vals
2273
2274    def sort(self, *args, **kwds):
2275        """Sort the values."""
2276        vals = self._main.values()
2277        vals.sort(*args, **kwds)
2278        self[:] = vals
2279
2280    def __mul__(self, n): return self._main.values()*n
2281    __rmul__ = __mul__
2282    def __add__(self, other): return self._main.values() + other
2283    def __radd__(self, other): return other + self._main.values()
2284
2285    ## following methods not implemented for values ##
2286    def __delitem__(self, i): raise TypeError('Can\'t delete items from values')
2287    def __iadd__(self, other): raise TypeError('Can\'t add in place to values')
2288    def __imul__(self, n): raise TypeError('Can\'t multiply values in place')
2289    def append(self, item): raise TypeError('Can\'t append items to values')
2290    def insert(self, i, item): raise TypeError('Can\'t insert items into values')
2291    def pop(self, i=-1): raise TypeError('Can\'t pop items from values')
2292    def remove(self, item): raise TypeError('Can\'t remove items from values')
2293    def extend(self, other): raise TypeError('Can\'t extend values')
2294
2295class SequenceOrderedDict(OrderedDict):
2296    """
2297    Experimental version of OrderedDict that has a custom object for ``keys``,
2298    ``values``, and ``items``.
2299   
2300    These are callable sequence objects that work as methods, or can be
2301    manipulated directly as sequences.
2302   
2303    Test for ``keys``, ``items`` and ``values``.
2304   
2305    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
2306    >>> d
2307    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
2308    >>> d.keys
2309    [1, 2, 3]
2310    >>> d.keys()
2311    [1, 2, 3]
2312    >>> d.setkeys((3, 2, 1))
2313    >>> d
2314    SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
2315    >>> d.setkeys((1, 2, 3))
2316    >>> d.keys[0]
2317    1
2318    >>> d.keys[:]
2319    [1, 2, 3]
2320    >>> d.keys[-1]
2321    3
2322    >>> d.keys[-2]
2323    2
2324    >>> d.keys[0:2] = [2, 1]
2325    >>> d
2326    SequenceOrderedDict([(2, 3), (1, 2), (3, 4)])
2327    >>> d.keys.reverse()
2328    >>> d.keys
2329    [3, 1, 2]
2330    >>> d.keys = [1, 2, 3]
2331    >>> d
2332    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
2333    >>> d.keys = [3, 1, 2]
2334    >>> d
2335    SequenceOrderedDict([(3, 4), (1, 2), (2, 3)])
2336    >>> a = SequenceOrderedDict()
2337    >>> b = SequenceOrderedDict()
2338    >>> a.keys == b.keys
2339    1
2340    >>> a['a'] = 3
2341    >>> a.keys == b.keys
2342    0
2343    >>> b['a'] = 3
2344    >>> a.keys == b.keys
2345    1
2346    >>> b['b'] = 3
2347    >>> a.keys == b.keys
2348    0
2349    >>> a.keys > b.keys
2350    0
2351    >>> a.keys < b.keys
2352    1
2353    >>> 'a' in a.keys
2354    1
2355    >>> len(b.keys)
2356    2
2357    >>> 'c' in d.keys
2358    0
2359    >>> 1 in d.keys
2360    1
2361    >>> [v for v in d.keys]
2362    [3, 1, 2]
2363    >>> d.keys.sort()
2364    >>> d.keys
2365    [1, 2, 3]
2366    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)), strict=True)
2367    >>> d.keys[::-1] = [1, 2, 3]
2368    >>> d
2369    SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
2370    >>> d.keys[:2]
2371    [3, 2]
2372    >>> d.keys[:2] = [1, 3]
2373    Traceback (most recent call last):
2374    KeyError: 'Keylist is not the same as current keylist.'
2375
2376    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
2377    >>> d
2378    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
2379    >>> d.values
2380    [2, 3, 4]
2381    >>> d.values()
2382    [2, 3, 4]
2383    >>> d.setvalues((4, 3, 2))
2384    >>> d
2385    SequenceOrderedDict([(1, 4), (2, 3), (3, 2)])
2386    >>> d.values[::-1]
2387    [2, 3, 4]
2388    >>> d.values[0]
2389    4
2390    >>> d.values[-2]
2391    3
2392    >>> del d.values[0]
2393    Traceback (most recent call last):
2394    TypeError: Can't delete items from values
2395    >>> d.values[::2] = [2, 4]
2396    >>> d
2397    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
2398    >>> 7 in d.values
2399    0
2400    >>> len(d.values)
2401    3
2402    >>> [val for val in d.values]
2403    [2, 3, 4]
2404    >>> d.values[-1] = 2
2405    >>> d.values.count(2)
2406    2
2407    >>> d.values.index(2)
2408    0
2409    >>> d.values[-1] = 7
2410    >>> d.values
2411    [2, 3, 7]
2412    >>> d.values.reverse()
2413    >>> d.values
2414    [7, 3, 2]
2415    >>> d.values.sort()
2416    >>> d.values
2417    [2, 3, 7]
2418    >>> d.values.append('anything')
2419    Traceback (most recent call last):
2420    TypeError: Can't append items to values
2421    >>> d.values = (1, 2, 3)
2422    >>> d
2423    SequenceOrderedDict([(1, 1), (2, 2), (3, 3)])
2424   
2425    >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
2426    >>> d
2427    SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
2428    >>> d.items()
2429    [(1, 2), (2, 3), (3, 4)]
2430    >>> d.setitems([(3, 4), (2 ,3), (1, 2)])
2431    >>> d
2432    SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
2433    >>> d.items[0]
2434    (3, 4)
2435    >>> d.items[:-1]
2436    [(3, 4), (2, 3)]
2437    >>> d.items[1] = (6, 3)
2438    >>> d.items
2439    [(3, 4), (6, 3), (1, 2)]
2440    >>> d.items[1:2] = [(9, 9)]
2441    >>> d
2442    SequenceOrderedDict([(3, 4), (9, 9), (1, 2)])
2443    >>> del d.items[1:2]
2444    >>> d
2445    SequenceOrderedDict([(3, 4), (1, 2)])
2446    >>> (3, 4) in d.items
2447    1
2448    >>> (4, 3) in d.items
2449    0
2450    >>> len(d.items)
2451    2
2452    >>> [v for v in d.items]
2453    [(3, 4), (1, 2)]
2454    >>> d.items.count((3, 4))
2455    1
2456    >>> d.items.index((1, 2))
2457    1
2458    >>> d.items.index((2, 1))
2459    Traceback (most recent call last):
2460    ValueError: list.index(x): x not in list
2461    >>> d.items.reverse()
2462    >>> d.items
2463    [(1, 2), (3, 4)]
2464    >>> d.items.reverse()
2465    >>> d.items.sort()
2466    >>> d.items
2467    [(1, 2), (3, 4)]
2468    >>> d.items.append((5, 6))
2469    >>> d.items
2470    [(1, 2), (3, 4), (5, 6)]
2471    >>> d.items.insert(0, (0, 0))
2472    >>> d.items
2473    [(0, 0), (1, 2), (3, 4), (5, 6)]
2474    >>> d.items.insert(-1, (7, 8))
2475    >>> d.items
2476    [(0, 0), (1, 2), (3, 4), (7, 8), (5, 6)]
2477    >>> d.items.pop()
2478    (5, 6)
2479    >>> d.items
2480    [(0, 0), (1, 2), (3, 4), (7, 8)]
2481    >>> d.items.remove((1, 2))
2482    >>> d.items
2483    [(0, 0), (3, 4), (7, 8)]
2484    >>> d.items.extend([(1, 2), (5, 6)])
2485    >>> d.items
2486    [(0, 0), (3, 4), (7, 8), (1, 2), (5, 6)]
2487    """
2488
2489    def __init__(self, init_val=(), strict=True):
2490        OrderedDict.__init__(self, init_val, strict=strict)
2491        self._keys = self.keys
2492        self._values = self.values
2493        self._items = self.items
2494        self.keys = Keys(self)
2495        self.values = Values(self)
2496        self.items = Items(self)
2497        self._att_dict = {
2498            'keys': self.setkeys,
2499            'items': self.setitems,
2500            'values': self.setvalues,
2501        }
2502
2503    def __setattr__(self, name, value):
2504        """Protect keys, items, and values."""
2505        if not '_att_dict' in self.__dict__:
2506            object.__setattr__(self, name, value)
2507        else:
2508            try:
2509                fun = self._att_dict[name]
2510            except KeyError:
2511                OrderedDict.__setattr__(self, name, value)
2512            else:
2513                fun(value)
2514
2515
2516
2517
2518#
2519# Imported from OrderedConfigParser.py
2520#
2521
2522#  _________________________________________________________________________
2523#
2524#  PyUtilib: A Python utility library.
2525#  Copyright (c) 2008 Sandia Corporation.
2526#  This software is distributed under the BSD License.
2527#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
2528#  the U.S. Government retains certain rights in this software.
2529#  _________________________________________________________________________
2530#
2531
2532import ConfigParser
2533import StringIO
2534
2535if not 'OrderedDict' in dir():
2536    from odict import OrderedDict
2537
2538
2539class OrderedConfigParser(ConfigParser.ConfigParser):
2540    """
2541    Customization of ConfigParser to (a) use an ordered dictionary and (b)
2542    keep the original case of the data keys.
2543    """
2544
2545    def __init__(self):
2546        if sys.version >= (2,6,0):
2547            ConfigParser.ConfigParser.__init__(self, dict_type=OrderedDict)
2548        else:
2549            ConfigParser.ConfigParser.__init__(self)
2550            self._defaults = OrderedDict()
2551            self._sections = OrderedDict()
2552
2553    def _get_sections(self, fp):
2554        """
2555        In old version of Python, we prefetch the sections, to
2556        ensure that the data structures we are using are OrderedDict.
2557        """
2558        if sys.version >= (2,6,0):
2559            return
2560        while True:
2561            line = fp.readline()
2562            if not line:
2563                break
2564            line.strip()
2565            mo = self.SECTCRE.match(line)
2566            if mo:
2567                sectname = mo.group('header')
2568                if not sectname in self._sections:
2569                    self._sections[sectname] = OrderedDict()
2570                    self._sections[sectname]['__name__'] = sectname
2571
2572    def _read(self, fp, fpname):
2573        """Parse a sectoned setup file.
2574
2575        This first calls _get_sections to preparse the section info,
2576        and then calls the ConfigParser._read method.
2577        """
2578        self._get_sections(fp)
2579        fp.seek(0)
2580        return ConfigParser.ConfigParser._read(self, fp, fpname)
2581
2582    def optionxform(self, option):
2583        """Do not convert to lower case"""
2584        return option
2585
2586
2587
2588#
2589# Imported from header.py
2590#
2591
2592#  _________________________________________________________________________
2593#
2594#  PyUtilib: A Python utility library.
2595#  Copyright (c) 2008 Sandia Corporation.
2596#  This software is distributed under the BSD License.
2597#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
2598#  the U.S. Government retains certain rights in this software.
2599#  _________________________________________________________________________
2600#
2601#
2602# This script was created with the virtualenv_install script.
2603#
2604
2605import commands
2606import re
2607import urllib2
2608import zipfile
2609import shutil
2610import string
2611import textwrap
2612import sys
2613import glob
2614import errno
2615import stat
2616
2617using_subversion = True
2618
2619#
2620# The following taken from PyUtilib
2621#
2622if (sys.platform[0:3] == "win"): #pragma:nocover
2623   executable_extension=".exe"
2624else:                            #pragma:nocover
2625   executable_extension=""
2626
2627
2628def search_file(filename, search_path=None, implicitExt=executable_extension, executable=False,         isfile=True):
2629    if search_path is None:
2630        #
2631        # Use the PATH environment if it is defined and not empty
2632        #
2633        if "PATH" in os.environ and os.environ["PATH"] != "":
2634            search_path = string.split(os.environ["PATH"], os.pathsep)
2635        else:
2636            search_path = os.defpath.split(os.pathsep)
2637    for path in search_path:
2638      if os.path.exists(os.path.join(path, filename)) and \
2639         (not isfile or os.path.isfile(os.path.join(path, filename))):
2640         if not executable or os.access(os.path.join(path,filename),os.X_OK):
2641            return os.path.abspath(os.path.join(path, filename))
2642      if os.path.exists(os.path.join(path, filename+implicitExt)) and \
2643         (not isfile or os.path.isfile(os.path.join(path, filename+implicitExt))):
2644         if not executable or os.access(os.path.join(path,filename+implicitExt),os.X_OK):
2645            return os.path.abspath(os.path.join(path, filename+implicitExt))
2646    return None
2647
2648#
2649# PyUtilib Ends
2650#
2651
2652
2653#
2654# The following taken from pkg_resources
2655#
2656component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
2657replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get
2658
2659def _parse_version_parts(s):
2660    for part in component_re.split(s):
2661        part = replace(part,part)
2662        if not part or part=='.':
2663            continue
2664        if part[:1] in '0123456789':
2665            yield part.zfill(8)    # pad for numeric comparison
2666        else:
2667            yield '*'+part
2668
2669    yield '*final'  # ensure that alpha/beta/candidate are before final
2670
2671def parse_version(s):
2672    parts = []
2673    for part in _parse_version_parts(s.lower()):
2674        if part.startswith('*'):
2675            if part<'*final':   # remove '-' before a prerelease tag
2676                while parts and parts[-1]=='*final-': parts.pop()
2677            # remove trailing zeros from each series of numeric parts
2678            while parts and parts[-1]=='00000000':
2679                parts.pop()
2680        parts.append(part)
2681    return tuple(parts)
2682#
2683# pkg_resources Ends
2684#
2685
2686#
2687# Use pkg_resources to guess version.
2688# This allows for parsing version with the syntax:
2689#   9.3.2
2690#   8.28.rc1
2691#
2692def guess_release(svndir):
2693    if using_subversion:
2694        output = commands.getoutput('svn ls '+svndir)
2695        if output=="":
2696            return None
2697        #print output
2698        versions = []
2699        for link in re.split('/',output.strip()):
2700            tmp = link.strip()
2701            if tmp != '':
2702                versions.append( tmp )
2703        #print versions
2704    else:
2705        if sys.version_info[:2] <= (2,5):
2706            output = urllib2.urlopen(svndir).read()
2707        else:
2708            output = urllib2.urlopen(svndir, timeout=30).read()
2709        if output=="":
2710            return None
2711        links = re.findall('\<li>\<a href[^>]+>[^\<]+\</a>',output)
2712        versions = []
2713        for link in links:
2714            versions.append( re.split('>', link[:-5])[-1] )
2715    latest = None
2716    latest_str = None
2717    for version in versions:
2718        if version is '.':
2719            continue
2720        v = parse_version(version)
2721        if latest is None or latest < v:
2722            latest = v
2723            latest_str = version
2724    if latest_str is None:
2725        return None
2726    if not latest_str[0] in '0123456789':
2727        return svndir
2728    return svndir+"/"+latest_str
2729
2730
2731
2732def zip_file(filename,fdlist):
2733    zf = zipfile.ZipFile(filename, 'w')
2734    for file in fdlist:
2735        if os.path.isdir(file):
2736            for root, dirs, files in os.walk(file):
2737                for fname in files:
2738                    if fname.endswith('exe'):
2739                        zf.external_attr = (0777 << 16L) | (010 << 28L)
2740                    else:
2741                        zf.external_attr = (0660 << 16L) | (010 << 28L)
2742                    zf.write(join(root,fname))
2743        else:
2744            zf.write(file)
2745    zf.close()
2746
2747
2748def unzip_file(filename, dir=None):
2749    fname = os.path.abspath(filename)
2750    zf = zipfile.ZipFile(fname, 'r')
2751    if dir is None:
2752        dir = os.getcwd()
2753    for file in zf.infolist():
2754        name = file.filename
2755        if name.endswith('/') or name.endswith('\\'):
2756            outfile = os.path.join(dir, name)
2757            if not os.path.exists(outfile):
2758                os.makedirs(outfile)
2759        else:
2760            outfile = os.path.join(dir, name)
2761            parent = os.path.dirname(outfile)
2762            if not os.path.exists(parent):
2763                os.makedirs(parent)
2764            OUTPUT = open(outfile, 'wb')
2765            OUTPUT.write(zf.read(name))
2766            OUTPUT.close()
2767    zf.close()
2768
2769
2770
2771class Repository(object):
2772
2773    svn_get='checkout'
2774    easy_install_path = ["easy_install"]
2775    python = "python"
2776    svn = "svn"
2777    dev = []
2778
2779    def __init__(self, name, root=None, trunk=None, stable=None, release=None, tag=None, pyname=None, pypi=None, dev=False, username=None, install=True, rev=None):
2780        class _TEMP_(object): pass
2781        self.config = _TEMP_()
2782        self.config.name=name
2783        self.config.root=root
2784        self.config.trunk=trunk
2785        self.config.stable=stable
2786        self.config.release=release
2787        self.config.tag=tag
2788        self.config.pyname=pyname
2789        self.config.pypi=pypi
2790        if dev == 'True' or dev is True:
2791            self.config.dev=True
2792        else:
2793            self.config.dev=False
2794        self.config.username=username
2795        if install == 'False' or install is False:
2796            self.config.install=False
2797        else:
2798            self.config.install=True
2799        self.config.rev=rev
2800        self.initialize(self.config)
2801
2802    def initialize(self, config):
2803        self.name = config.name
2804        self.root = config.root
2805        self.trunk = None
2806        self.trunk_root = None
2807        self.stable = None
2808        self.stable_root = None
2809        self.release = None
2810        self.tag = None
2811        self.release_root = None
2812        #
2813        self.pypi = config.pypi
2814        if not config.pypi is None:
2815            self.pyname=config.pypi
2816        else:
2817            self.pyname=config.pyname
2818        self.dev = config.dev
2819        if config.dev:
2820            Repository.dev.append(config.name)
2821        self.pkgdir = None
2822        self.pkgroot = None
2823        if config.username is None or '$' in config.username:
2824            self.svn_username = []
2825        else:
2826            self.svn_username = ['--username', config.username]
2827        if config.rev is None:
2828            self.rev=''
2829            self.revarg=[]
2830        else:
2831            self.rev='@'+config.rev
2832            self.revarg=['-r',config.rev]
2833        self.install = config.install
2834
2835    def guess_versions(self, offline=False):
2836        if not self.config.root is None:
2837            if using_subversion:
2838                rootdir_output = commands.getoutput('svn ls ' + self.config.root)
2839            else:
2840                if sys.version_info[:2] <= (2,5):
2841                    rootdir_output = urllib2.urlopen(self.config.root).read()
2842                else:
2843                    rootdir_output = urllib2.urlopen(self.config.root, timeout=30).read()
2844            try:
2845                self.trunk = self.config.root+'/trunk'
2846                self.trunk_root = self.trunk
2847            except urllib2.HTTPError:
2848                self.trunk = None
2849                self.trunk_root = None
2850            try:
2851                if offline or not 'stable' in rootdir_output:
2852                    raise IOError
2853                self.stable = guess_release(self.config.root+'/stable')
2854                self.stable_root = self.stable
2855            except (urllib2.HTTPError,IOError):
2856                self.stable = None
2857                self.stable_root = None
2858            try:
2859                if offline or not 'releases' in rootdir_output:
2860                    raise IOError
2861                self.release = guess_release(self.config.root+'/releases')
2862                self.tag = None
2863                self.release_root = self.release
2864            except (urllib2.HTTPError,IOError):
2865                try:
2866                    if offline or not 'tags' in rootdir_output:
2867                        raise IOError
2868                    self.release = guess_release(self.config.root+'/tags')
2869                    self.tag = self.release
2870                    self.release_root = self.release
2871                except (urllib2.HTTPError,IOError):
2872                    self.release = None
2873                    self.release_root = None
2874        if not self.config.trunk is None:
2875            if self.trunk is None:
2876                self.trunk = self.config.trunk
2877            else:
2878                self.trunk += self.config.trunk
2879        if not self.config.stable is None:
2880            if self.stable is None:
2881                self.stable = self.config.stable
2882            else:
2883                self.stable += self.config.stable
2884        if not self.config.release is None:
2885            if self.release is None:
2886                self.release = self.config.release
2887            else:
2888                self.release += self.config.release
2889        if not self.config.tag is None:
2890            if self.release is None:
2891                self.release = self.config.tag
2892            else:
2893                self.release += self.config.tag
2894
2895
2896    def write_config(self, OUTPUT):
2897        config = self.config
2898        print >>OUTPUT, '[%s]' % config.name
2899        if not config.root is None:
2900            print >>OUTPUT, 'root=%s' % config.root
2901        if not config.trunk is None:
2902            print >>OUTPUT, 'trunk=%s' % config.trunk
2903        if not config.stable is None:
2904            print >>OUTPUT, 'stable=%s' % config.stable
2905        if not config.tag is None:
2906            print >>OUTPUT, 'tag=%s' % config.tag
2907        elif not config.release is None:
2908            print >>OUTPUT, 'release=%s' % config.release
2909        if not config.pypi is None:
2910            print >>OUTPUT, 'pypi=%s' % config.pypi
2911        elif not config.pyname is None:
2912            print >>OUTPUT, 'pypi=%s' % config.pyname
2913        print >>OUTPUT, 'dev=%s' % str(config.dev)
2914        print >>OUTPUT, 'install=%s' % str(config.install)
2915        if not config.rev is None:
2916            print >>OUTPUT, 'rev=%s' % str(config.rev)
2917        if not config.username is None:
2918            print >>OUTPUT, 'username=%s' % str(config.username)
2919
2920
2921    def find_pkgroot(self, trunk=False, stable=False, release=False):
2922        if trunk:
2923            if self.trunk is None:
2924                if not self.stable is None:
2925                    self.find_pkgroot(stable=True)
2926                elif self.pypi is None:
2927                    self.find_pkgroot(release=True)
2928                else:
2929                    # use easy_install
2930                    self.pkgdir = None
2931                    self.pkgroot = None
2932                    return
2933            else:
2934                self.pkgdir = self.trunk
2935                self.pkgroot = self.trunk_root
2936                return
2937
2938        elif stable:
2939            if self.stable is None: 
2940                if not self.release is None:
2941                    self.find_pkgroot(release=True)
2942                elif self.pypi is None:
2943                    self.find_pkgroot(trunk=True)
2944                else:
2945                    # use easy_install
2946                    self.pkgdir = None
2947                    self.pkgroot = None
2948                    return
2949            else:
2950                self.pkgdir = self.stable
2951                self.pkgroot = self.stable_root
2952                return
2953
2954        elif release:
2955            if self.release is None:
2956                if not self.stable is None:
2957                    self.find_pkgroot(stable=True)
2958                elif self.pypi is None:
2959                    self.find_pkgroot(trunk=True)
2960                else:
2961                    # use easy_install
2962                    self.pkgdir = None
2963                    self.pkgroot = None
2964                    return
2965            else:
2966                self.pkgdir = self.release
2967                self.pkgroot = self.release_root
2968
2969        else:
2970            raise IOError, "Must have one of trunk, stable or release specified"
2971           
2972
2973    def install_trunk(self, dir=None, install=True, preinstall=False, offline=False):
2974        self.find_pkgroot(trunk=True)
2975        self.perform_install(dir=dir, install=install, preinstall=preinstall, offline=offline)
2976       
2977    def install_stable(self, dir=None, install=True, preinstall=False, offline=False):
2978        self.find_pkgroot(stable=True)
2979        self.perform_install(dir=dir, install=install, preinstall=preinstall, offline=offline)
2980       
2981    def install_release(self, dir=None, install=True, preinstall=False, offline=False):
2982        self.find_pkgroot(release=True)
2983        self.perform_install(dir=dir, install=install, preinstall=preinstall, offline=offline)
2984       
2985    def perform_install(self, dir=None, install=True, preinstall=False, offline=False):
2986        if self.pkgdir is None:
2987            self.easy_install(install, preinstall, dir, offline)
2988            return
2989        print "-----------------------------------------------------------------"
2990        print "  Installing branch"
2991        print "  Checking out source for package",self.name
2992        print "     Subversion dir: "+self.pkgdir
2993        if os.path.exists(dir):
2994            print "     No checkout required"
2995            print "-----------------------------------------------------------------"
2996        else:
2997            print "-----------------------------------------------------------------"
2998            self.run([self.svn]+self.svn_username+[Repository.svn_get,'-q',self.pkgdir+self.rev, dir])
2999        if install:
3000            if self.dev:
3001                self.run([self.python, 'setup.py', 'develop'], dir=dir)
3002            else:
3003                self.run([self.python, 'setup.py', 'install'], dir=dir)
3004
3005    def update_trunk(self, dir=None):
3006        self.find_pkgroot(trunk=True)
3007        self.perform_update(dir=dir)
3008
3009    def update_stable(self, dir=None):
3010        self.find_pkgroot(stable=True)
3011        self.perform_update(dir=dir)
3012
3013    def update_release(self, dir=None):
3014        self.find_pkgroot(release=True)
3015        self.perform_update(dir=dir)
3016
3017    def perform_update(self, dir=None):
3018        if self.pkgdir is None:
3019            self.easy_upgrade()
3020            return
3021        print "-----------------------------------------------------------------"
3022        print "  Updating branch"
3023        print "  Updating source for package",self.name
3024        print "     Subversion dir: "+self.pkgdir
3025        print "     Source dir:     "+dir
3026        print "-----------------------------------------------------------------"
3027        self.run([self.svn,'update','-q']+self.revarg+[dir])
3028        if self.dev:
3029            self.run([self.python, 'setup.py', 'develop'], dir=dir)
3030        else:
3031            self.run([self.python, 'setup.py', 'install'], dir=dir)
3032
3033    def Xsdist_trunk(self, format='zip'):
3034        if self.trunk is None:
3035            if not self.pypi is None:
3036                self.easy_install()
3037            elif not self.stable is None:
3038                self.sdist_stable(format=format)
3039            else:
3040                self.sdist_release(format=format)
3041        else:
3042            self.pkgdir=self.trunk
3043            self.pkgroot=self.trunk_root
3044            print "-----------------------------------------------------------------"
3045            print "  Checking out source for package",self.name
3046            print "     Subversion dir: "+self.trunk
3047            print "-----------------------------------------------------------------"
3048            self.run([self.svn]+self.svn_username+[Repository.svn_get,'-q',self.trunk, 'pkg'+self.name+self.rev])
3049            self.run([self.python, 'setup.py', 'sdist','-q','--dist-dir=..', '--formats='+format], dir='pkg'+self.name)
3050            os.chdir('..')
3051            rmtree('pkg'+self.name)
3052
3053    def Xsdist_stable(self, format='zip'):
3054        if self.stable is None:
3055            if not self.pypi is None:
3056                self.easy_install()
3057            elif not self.release is None:
3058                self.install_release()
3059            elif not self.trunk is None:
3060                self.install_trunk()
3061        else:
3062            self.pkgdir=self.stable
3063            self.pkgroot=self.stable_root
3064            print "-----------------------------------------------------------------"
3065            print "  Checking out source for package",self.name
3066            print "     Subversion dir: "+self.stable
3067            print "     Source dir:     "+dir
3068            print "-----------------------------------------------------------------"
3069            self.run([self.svn]+self.svn_username+[Repository.svn_get,'-q',self.stable, dir])
3070            self.run([self.python, 'setup.py', 'develop'], dir=dir)
3071
3072    def Xsdist_release(self, dir=None):
3073        if self.release is None:
3074            if not self.pypi is None:
3075                self.easy_install()
3076            elif not self.stable is None:
3077                self.install_stable()
3078            elif not self.trunk is None:
3079                self.install_trunk()
3080        else:
3081            self.pkgdir=self.release
3082            self.pkgroot=self.release_root
3083            print "-----------------------------------------------------------------"
3084            print "  Checking out source for package",self.name
3085            print "     Subversion dir: "+self.release
3086            print "     Source dir:     "+dir
3087            print "-----------------------------------------------------------------"
3088            self.run([self.svn]+self.svn_username+[Repository.svn_get]+self.rev+['-q',self.release, dir])
3089            self.run([self.python, 'setup.py', 'install'], dir=dir)
3090
3091    def easy_install(self, install, preinstall, dir, offline):
3092        try:
3093            if install:
3094                #self.run([self.easy_install_path, '-q', self.pypi])
3095                if offline:
3096                    self.run([self.python, 'setup.py', 'install'], dir=dir)
3097                else:
3098                    self.run(self.easy_install_path + ['-q', self.pypi])
3099            elif preinstall: 
3100                if not os.path.exists(dir):
3101                    self.run(self.easy_install_path + ['-q', '--editable', '--build-directory', '.', self.pypi], dir=os.path.dirname(dir))
3102        except OSError, err:
3103            print "-----------------------------------------------------------------"
3104            print "Warning!!! Ignoring easy_install error '%s'" % str(err)
3105            print "-----------------------------------------------------------------"
3106
3107    def easy_upgrade(self):
3108        self.run(self.easy_install_path + ['-q', '--upgrade', self.pypi])
3109
3110    def run(self, cmd, dir=None):
3111        cwd=os.getcwd()
3112        if not dir is None:
3113            os.chdir(dir)
3114            cwd=dir
3115        print "Running command '%s' in directory %s" % (" ".join(cmd), cwd)
3116        call_subprocess(cmd, filter_stdout=filter_python_develop, show_stdout=True)
3117        if not dir is None:
3118            os.chdir(cwd)
3119
3120
3121if sys.platform.startswith('win'):
3122    if not is_jython:
3123        Repository.python += '.exe'
3124    Repository.svn += '.exe'
3125
3126
3127def filter_python_develop(line):
3128    if not line.strip():
3129        return Logger.DEBUG
3130    for prefix in ['Searching for', 'Reading ', 'Best match: ', 'Processing ',
3131                   'Moving ', 'Adding ', 'running ', 'writing ', 'Creating ',
3132                   'creating ', 'Copying ']:
3133        if line.startswith(prefix):
3134            return Logger.DEBUG
3135    return Logger.NOTIFY
3136
3137
3138def apply_template(str, d):
3139    t = string.Template(str)
3140    return t.safe_substitute(d)
3141
3142
3143wrapper = textwrap.TextWrapper(subsequent_indent="    ")
3144
3145
3146class Installer(object):
3147
3148    def __init__(self):
3149        self.description="This script manages the installation of packages into a virtual Python installation."
3150        self.home_dir = None
3151        self.default_dirname='python'
3152        self.abshome_dir = None
3153        self.sw_packages = []
3154        self.sw_dict = {}
3155        self.cmd_files = []
3156        self.auxdir = []
3157        self.config=None
3158        self.config_file=None
3159        self.README="""
3160#
3161# Virtual Python installation generated by the %s script.
3162#
3163# This directory is managed with virtualenv, which creates a
3164# virtual Python installation.  If the 'bin' directory is put in
3165# user's PATH environment, then the bin/python command can be used
3166# without further installation.
3167#
3168# Directories:
3169#   admin      Administrative data for maintaining this distribution
3170#   bin        Scripts and executables
3171#   dist       Python packages that are not intended for development
3172#   include    Python header files
3173#   lib        Python libraries and installed packages
3174#   src        Python packages whose source files can be
3175#              modified and used directly within this virtual Python
3176#              installation.
3177#   Scripts    Python bin directory (used on MS Windows)
3178#
3179""" % sys.argv[0]
3180
3181    def add_repository(self, *args, **kwds):
3182        if not 'root' in kwds and not 'pypi' in kwds and not 'release' in kwds and not 'trunk' in kwds and not 'stable' in kwds:
3183            raise IOError, "No repository info specified for repository "+args[0]
3184        repos = Repository( *args, **kwds)
3185        self.sw_dict[repos.name] = repos
3186        self.sw_packages.append( repos )
3187
3188    def add_dos_cmd(self, file):
3189        self.cmd_files.append( file )
3190
3191    def add_auxdir(self, package, todir, fromdir):
3192        self.auxdir.append( (todir, package, fromdir) )
3193
3194    def modify_parser(self, parser):
3195        self.default_windir = 'C:\\'+self.default_dirname
3196        self.default_unixdir = './'+self.default_dirname
3197        #
3198        parser.add_option('--debug',
3199            help='Configure script to generate debugging IO and to raise exceptions.',
3200            action='store_true',
3201            dest='debug',
3202            default=False)
3203
3204        parser.add_option('--trunk',
3205            help='Install trunk branches of Python software.',
3206            action='store_true',
3207            dest='trunk',
3208            default=False)
3209
3210        parser.add_option('--stable',
3211            help='Install stable branches of Python software.',
3212            action='store_true',
3213            dest='stable',
3214            default=False)
3215
3216        parser.add_option('--update',
3217            help='Update all Python packages.',
3218            action='store_true',
3219            dest='update',
3220            default=False)
3221
3222        parser.add_option('--proxy',
3223            help='Set the HTTP_PROXY environment with this option.',
3224            action='store',
3225            dest='proxy',
3226            default=None)
3227
3228        parser.add_option('--preinstall',
3229            help='Prepare an installation that will be used to build a MS Windows installer.',
3230            action='store_true',
3231            dest='preinstall',
3232            default=False)
3233
3234        parser.add_option('--offline',
3235            help='Perform installation offline, using source extracted from ZIP files.',
3236            action='store_true',
3237            dest='offline',
3238            default=False)
3239
3240        parser.add_option('--zip',
3241            help='Add ZIP files that are use define this installation.',
3242            action='append',
3243            dest='zip',
3244            default=[])
3245
3246        parser.add_option('--use-pythonpath',
3247            help="By default, the PYTHONPATH is ignored when installing.  This option allows the 'easy_install' tool to search this path for related Python packages, which are then installed.",
3248            action='store_true',
3249            dest='use_pythonpath',
3250            default=False)
3251
3252        parser.add_option(
3253            '--site-packages',
3254            dest='no_site_packages',
3255            action='store_false',
3256            help="Setup the virtual environment to use the global site-packages",
3257            default=True)
3258
3259        parser.add_option('--config',
3260            help='Use an INI config file to specify the packages used in this installation.  Using this option clears the initial configuration, but multiple uses of this option will add package specifications.',
3261            action='append',
3262            dest='config_files',
3263            default=[])
3264
3265        parser.add_option('--keep-config',
3266            help='Keep the initial configuration data that was specified if the --config option is specified.',
3267            action='store_true',
3268            dest='keep_config',
3269            default=False)
3270
3271        parser.add_option('--localize',
3272            help='Force localization of DOS scripts on Linux platforms',
3273            action='store_true',
3274            dest='localize',
3275            default=False)
3276
3277        #
3278        # Change the virtualenv options
3279        #
3280        parser.remove_option("--python")
3281        parser.add_option("--python",
3282            dest='python',
3283            metavar='PYTHON_EXE',
3284            help="Specify the Python interpreter to use, e.g., --python=python2.5 will install with the python2.5 interpreter.")
3285        parser.remove_option("--relocatable")
3286        parser.remove_option("--version")
3287        parser.remove_option("--unzip-setuptools")
3288        parser.remove_option("--no-site-packages")
3289        parser.remove_option("--clear")
3290        #
3291        # Add description
3292        #
3293        parser.description=self.description
3294        parser.epilog="If DEST_DIR is not specified, then a default installation path is used:  "+self.default_windir+" on Windows and "+self.default_unixdir+" on Linux.  This command uses the Python 'setuptools' package to install Python packages.  This package installs packages by downloading files from the internet.  If you are running this from within a firewall, you may need to set the HTTP_PROXY environment variable to a value like 'http://<proxyhost>:<port>'."
3295       
3296
3297    def adjust_options(self, options, args):
3298        #
3299        # Force options.clear to be False.  This allows us to preserve the logic
3300        # associated with --clear, which we may want to use later.
3301        #
3302        options.clear=False
3303        #
3304        global vpy_main
3305        if options.debug:
3306            vpy_main.raise_exceptions=True
3307        #
3308        global logger
3309        verbosity = options.verbose - options.quiet
3310        self.logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
3311        logger = self.logger
3312        #
3313        if options.update and (options.stable or options.trunk):
3314            self.logger.fatal("ERROR: cannot specify --stable or --trunk when specifying the --update option.")
3315            sys.exit(1000)
3316        if options.update and len(options.config_files) > 0:
3317            self.logger.fatal("ERROR: cannot specify --config when specifying the --update option.")
3318            sys.exit(1000)
3319        if options.update and options.keep_config:
3320            self.logger.fatal("ERROR: cannot specify --keep-config when specifying the --update option.")
3321            sys.exit(1000)
3322        if len(args) > 1:
3323            self.logger.fatal("ERROR: installer script can only have one argument")
3324            sys.exit(1000)
3325        #
3326        # Error checking
3327        #
3328        if not options.preinstall and (os.path.exists(self.abshome_dir) ^ options.update):
3329            if options.update:
3330                self.logger.fatal(wrapper.fill("ERROR: The 'update' option is specified, but the installation path '%s' does not exist!" % self.home_dir))
3331                sys.exit(1000)
3332            elif os.path.exists(join(self.abshome_dir,'bin')):
3333                    self.logger.fatal(wrapper.fill("ERROR: The installation path '%s' already exists!  Use the --update option if you wish to update, or remove this directory to create a fresh installation." % self.home_dir))
3334                    sys.exit(1000)
3335        if len(args) == 0:
3336            args.append(self.abshome_dir)
3337        #
3338        # Parse config files
3339        #
3340        if options.update:
3341            self.config=None
3342            options.config_files.append( join(self.abshome_dir, 'admin', 'config.ini') )
3343        if not self.config is None and (len(options.config_files) == 0 or options.keep_config):
3344            fp = StringIO.StringIO(self.config)
3345            self.read_config_file(fp=fp)
3346            fp.close()
3347        if not self.config_file is None and (len(options.config_files) == 0 or options.keep_config):
3348            self.read_config_file(file=self.config_file)
3349        for file in options.config_files:
3350            self.read_config_file(file=file)
3351        print "-----------------------------------------------------------------"
3352        print "Finished processing configuration information."
3353        print "-----------------------------------------------------------------"
3354        print " START - Configuration summary"
3355        print "-----------------------------------------------------------------"
3356        self.write_config(stream=sys.stdout)
3357        print "-----------------------------------------------------------------"
3358        print " END - Configuration summary"
3359        print "-----------------------------------------------------------------"
3360        #
3361        # If applying preinstall, then only do subversion exports
3362        #
3363        if options.preinstall:
3364            Repository.svn_get='export'
3365
3366    def get_homedir(self, options, args):
3367        #
3368        # Figure out the installation directory
3369        #
3370        if len(args) == 0:
3371            path = self.guess_path()
3372            if path is None or options.preinstall:
3373                # Install in a default location.
3374                if sys.platform == 'win32':
3375                    home_dir = self.default_windir
3376                else:
3377                    home_dir = self.default_unixdir
3378            else:
3379                home_dir = os.path.dirname(os.path.dirname(path))
3380        else:
3381            home_dir = args[0]
3382        self.home_dir = home_dir
3383        self.abshome_dir = os.path.abspath(home_dir)
3384
3385    def guess_path(self):
3386        return None
3387
3388    def setup_installer(self, options):
3389        if options.preinstall:
3390            print "Creating preinstall zip file in '%s'" % self.home_dir
3391        elif options.update:
3392            print "Updating existing installation in '%s'" % self.home_dir
3393        else:
3394            print "Starting fresh installation in '%s'" % self.home_dir
3395        #
3396        # Setup HTTP proxy
3397        #
3398        if options.offline:
3399            os.environ['HTTP_PROXY'] = ''
3400            os.environ['http_proxy'] = ''
3401        else:
3402            proxy = ''
3403            if not options.proxy is None:
3404                proxy = options.proxy
3405            if proxy is '':
3406                proxy = os.environ.get('HTTP_PROXY', '')
3407            if proxy is '':
3408                proxy = os.environ.get('http_proxy', '')
3409            os.environ['HTTP_PROXY'] = proxy
3410            os.environ['http_proxy'] = proxy
3411            print "  using the HTTP_PROXY environment: %s" % proxy
3412            print ""
3413        #
3414        # Disable the PYTHONPATH, to isolate this installation from
3415        # other Python installations that a user may be working with.
3416        #
3417        if not options.use_pythonpath:
3418            try:
3419                del os.environ["PYTHONPATH"]
3420            except:
3421                pass
3422        #
3423        # If --preinstall is declared, then we remove the directory, and prepare a ZIP file
3424        # that contains the full installation.
3425        #
3426        if options.preinstall:
3427            print "-----------------------------------------------------------------"
3428            print " STARTING preinstall in directory %s" % self.home_dir
3429            print "-----------------------------------------------------------------"
3430            rmtree(self.abshome_dir)
3431            os.mkdir(self.abshome_dir)
3432        #
3433        # When preinstalling or working offline, disable the
3434        # default install_setuptools() function.
3435        #
3436        if options.offline:
3437            install_setuptools.use_default=False
3438            install_pip.use_default=False
3439        #
3440        # If we're clearing the current installation, then remove a bunch of
3441        # directories
3442        #
3443        elif options.clear:
3444            path = join(self.abshome_dir,'src')
3445            if os.path.exists(path):
3446                rmtree(path)
3447        #
3448        # Open up zip files
3449        #
3450        for file in options.zip:
3451            unzip_file(file, dir=self.abshome_dir)
3452
3453        if options.preinstall or not options.offline:
3454            #self.get_packages(options)
3455            pass
3456        else:
3457            self.sw_packages.insert( 0, Repository('virtualenv', pypi='virtualenv') )
3458            self.sw_packages.insert( 0, Repository('pip', pypi='pip') )
3459            self.sw_packages.insert( 0, Repository('setuptools', pypi='setuptools') )
3460            #
3461            # Configure the package versions, for offline installs
3462            #
3463            for pkg in self.sw_packages:
3464                pkg.guess_versions(True)
3465
3466    def get_packages(self, options):
3467        #
3468        # Setup the 'admin' directory
3469        #
3470        if not os.path.exists(self.abshome_dir):
3471            os.mkdir(self.abshome_dir)
3472        if not os.path.exists(join(self.abshome_dir,'admin')):
3473            os.mkdir(join(self.abshome_dir,'admin'))
3474        if options.update:
3475            INPUT=open(join(self.abshome_dir,'admin',"virtualenv.cfg"),'r')
3476            options.trunk = INPUT.readline().strip() != 'False'
3477            options.stable = INPUT.readline().strip() != 'False'
3478            INPUT.close()
3479        else:
3480            OUTPUT=open(join(self.abshome_dir,'admin',"virtualenv.cfg"),'w')
3481            print >>OUTPUT, options.trunk
3482            print >>OUTPUT, options.stable
3483            OUTPUT.close()
3484            self.write_config( join(self.abshome_dir,'admin','config.ini') )
3485        #
3486        # Setup package directories
3487        #
3488        if not os.path.exists(join(self.abshome_dir,'dist')):
3489            os.mkdir(join(self.abshome_dir,'dist'))
3490        if not os.path.exists(self.abshome_dir+os.sep+"src"):
3491            os.mkdir(self.abshome_dir+os.sep+"src")
3492        if not os.path.exists(self.abshome_dir+os.sep+"bin"):
3493            os.mkdir(self.abshome_dir+os.sep+"bin")
3494        #
3495        # Get source packages
3496        #
3497        self.sw_packages.insert( 0, Repository('virtualenv', pypi='virtualenv') )
3498        self.sw_packages.insert( 0, Repository('pip', pypi='pip') )
3499        if options.preinstall:
3500            #
3501            # When preinstalling, add the setuptools package to the installation list
3502            #
3503            self.sw_packages.insert( 0, Repository('setuptools', pypi='setuptools') )
3504        #
3505        # Add Coopr Forum packages
3506        #
3507        self.get_other_packages(options)
3508        #
3509        # Get package source
3510        #
3511        for pkg in self.sw_packages:
3512            pkg.guess_versions(False)
3513            if not pkg.install:
3514                pkg.find_pkgroot(trunk=options.trunk, stable=options.stable, release=not (options.trunk or options.stable))
3515                continue
3516            if pkg.dev:
3517                tmp = join(self.abshome_dir,'src',pkg.name)
3518            else:
3519                tmp = join(self.abshome_dir,'dist',pkg.name)
3520            if options.trunk:
3521                if not options.update:
3522                    pkg.install_trunk(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3523            elif options.stable:
3524                if not options.update:
3525                    pkg.install_stable(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3526            else:
3527                if not options.update:
3528                    pkg.install_release(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3529        if options.update or not os.path.exists(join(self.abshome_dir,'doc')):
3530            self.install_auxdirs(options)
3531        #
3532        # Create a README.txt file
3533        #
3534        OUTPUT=open(join(self.abshome_dir,"README.txt"),"w")
3535        print >>OUTPUT, self.README.strip()
3536        OUTPUT.close()
3537        #
3538        # Finalize preinstall
3539        #
3540        if options.preinstall:
3541            print "-----------------------------------------------------------------"
3542            print " FINISHED preinstall in directory %s" % self.home_dir
3543            print "-----------------------------------------------------------------"
3544            os.chdir(self.abshome_dir)
3545            zip_file(self.default_dirname+'.zip', ['.'])
3546            sys.exit(0)
3547
3548    def get_other_packages(self, options):
3549        #
3550        # Used by subclasses of Installer to
3551        # add packages that were requested through other means....
3552        #
3553        pass
3554       
3555    def install_packages(self, options):
3556        #
3557        # Set the bin directory
3558        #
3559        if os.path.exists(self.abshome_dir+os.sep+"Scripts"):
3560            bindir = join(self.abshome_dir,"Scripts")
3561        else:
3562            bindir = join(self.abshome_dir,"bin")
3563        if is_jython:
3564            Repository.python = os.path.abspath(join(bindir, 'jython.bat'))
3565        else:
3566            Repository.python = os.path.abspath(join(bindir, 'python'))
3567        if os.path.exists(os.path.abspath(join(bindir, 'easy_install'))):
3568            Repository.easy_install_path = [Repository.python, os.path.abspath(join(bindir, 'easy_install'))]
3569        else:
3570            Repository.easy_install_path = [os.path.abspath(join(bindir, 'easy_install.exe'))]
3571        #
3572        if options.preinstall or not options.offline:
3573            self.get_packages(options)
3574        #
3575        # Install the related packages
3576        #
3577        for pkg in self.sw_packages:
3578            if not pkg.install:
3579                pkg.find_pkgroot(trunk=options.trunk, stable=options.stable, release=not (options.trunk or options.stable))
3580                continue
3581            if pkg.dev:
3582                srcdir = join(self.abshome_dir,'src',pkg.name)
3583            else:
3584                srcdir = join(self.abshome_dir,'dist',pkg.name)
3585            if options.trunk:
3586                if options.update:
3587                    pkg.update_trunk(dir=srcdir)
3588                else:
3589                    pkg.install_trunk(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3590            elif options.stable:
3591                if options.update:
3592                    pkg.update_stable(dir=srcdir)
3593                else:
3594                    pkg.install_stable(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3595            else:
3596                if options.update:
3597                    pkg.update_release(dir=srcdir)
3598                else:
3599                    pkg.install_release(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3600        #
3601        # Copy the <env>/Scripts/* files into <env>/bin
3602        #
3603        if os.path.exists(self.abshome_dir+os.sep+"Scripts"):
3604            for file in glob.glob(self.abshome_dir+os.sep+"Scripts"+os.sep+"*"):
3605                shutil.copy(file, self.abshome_dir+os.sep+"bin")
3606        #
3607        # Localize DOS cmd files
3608        #
3609        self.localize_cmd_files(self.abshome_dir, options.localize)
3610        #
3611        # Misc notifications
3612        #
3613        if not options.update:
3614            print ""
3615            print "-----------------------------------------------------------------"
3616            print "  Add %s to the PATH environment variable" % (self.home_dir+os.sep+"bin")
3617            print "-----------------------------------------------------------------"
3618        print ""
3619        print "Finished installation in '%s'" % self.home_dir
3620
3621    def localize_cmd_files(self, dir, force_localization=False):
3622        """
3623        Hard-code the path to Python that is used in the Python CMD files that
3624        are installed.
3625        """
3626        if not (sys.platform.startswith('win') or force_localization):
3627            return
3628        for file in self.cmd_files:
3629            INPUT = open(join(dir,'bin',file), 'r')
3630            content = "".join(INPUT.readlines())
3631            INPUT.close()
3632            content = content.replace('__VIRTUAL_ENV__',dir)
3633            OUTPUT = open(join(dir,'bin',file), 'w')
3634            OUTPUT.write(content)
3635            OUTPUT.close()
3636
3637    def svnjoin(*args):
3638        return '/'.join(args[1:])
3639
3640    def install_auxdirs(self, options):
3641        for todir,pkg,fromdir in self.auxdir:
3642            pkgroot = self.sw_dict[pkg].pkgroot
3643            if options.update:
3644                cmd = [Repository.svn,'update','-q',self.svnjoin(self.abshome_dir, todir)]
3645            else:
3646                if options.clear:
3647                    rmtree( join(self.abshome_dir,todir) )
3648                cmd = [Repository.svn,Repository.svn_get,'-q',self.svnjoin(pkgroot,fromdir),join(self.abshome_dir,todir)]
3649            print "Running command '%s'" % " ".join(cmd)
3650            call_subprocess(cmd, filter_stdout=filter_python_develop,show_stdout=True)
3651
3652    def read_config_file(self, file=None, fp=None):
3653        """
3654        Read a config file.
3655        """
3656        parser = OrderedConfigParser()
3657        if not fp is None:
3658            parser.readfp(fp, '<default configuration>')
3659        elif not os.path.exists(file):
3660            if not '/' in file and not self.config_file is None:
3661                file = os.path.dirname(self.config_file)+"/"+file
3662            try:
3663                if sys.version_info[:2] <= (2,5):
3664                    output = urllib2.urlopen(file).read()
3665                else:
3666                    output = urllib2.urlopen(file, timeout=30).read()
3667            except Exception, err:
3668                print "Problems opening configuration url:",file
3669                raise
3670            fp = StringIO.StringIO(output)
3671            parser.readfp(fp, file)
3672            fp.close()
3673        else:
3674            if not file in parser.read(file):
3675                raise IOError, "Error while parsing file %s." % file
3676        sections = parser.sections()
3677        if 'installer' in sections:
3678            for option, value in parser.items('installer'):
3679                setattr(self, option, apply_template(value, os.environ) )
3680        if 'localize' in sections:
3681            for option, value in parser.items('localize'):
3682                self.add_dos_cmd(option)
3683        for sec in sections:
3684            if sec in ['installer', 'localize']:
3685                continue
3686            if sec.endswith(':auxdir'):
3687                auxdir = sec[:-7]
3688                for option, value in parser.items(sec):
3689                    self.add_auxdir(auxdir, option, apply_template(value, os.environ) )
3690            else:
3691                options = {}
3692                for option, value in parser.items(sec):
3693                    options[option] = apply_template(value, os.environ)
3694                self.add_repository(sec, **options)
3695
3696    def write_config(self, filename=None, stream=None):
3697        if not filename is None:
3698            OUTPUT=open(filename,'w')
3699            self.write_config(stream=OUTPUT)
3700            OUTPUT.close()
3701        else: 
3702            for repos in self.sw_packages:
3703                repos.write_config(stream)
3704                print >>stream, ""
3705            if len(self.cmd_files) > 0:
3706                print >>stream, "[localize]"
3707                for file in self.cmd_files:
3708                    print >>stream, file+"="
3709                print >>stream, "\n"
3710       
3711
3712
3713def configure(installer):
3714    """
3715    A dummy configuration function.
3716    """
3717    return installer
3718
3719def create_installer():
3720    return Installer()
3721
3722def get_installer():
3723    """
3724    Return an instance of the installer object.  If this object
3725    does not already exist, then create the object and use the
3726    configure() function to customize it based on the end-user's
3727    needs.
3728
3729    The argument to this function is the class type that will be
3730    constructed if needed.
3731    """
3732    try:
3733        return get_installer.installer
3734    except:
3735        get_installer.installer = configure( create_installer() )
3736        return get_installer.installer
3737   
3738
3739#
3740# Override the default definition of rmtree, to better handle MSWindows errors
3741# that are associated with read-only files
3742#
3743def handleRemoveReadonly(func, path, exc):
3744  excvalue = exc[1]
3745  if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
3746      os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
3747      func(path)
3748  else:
3749      raise
3750
3751def rmtree(dir):
3752    if os.path.exists(dir):
3753        logger.notify('Deleting tree %s', dir)
3754        shutil.rmtree(dir, ignore_errors=False, onerror=handleRemoveReadonly)
3755    else:
3756        logger.info('Do not need to delete %s; already gone', dir)
3757
3758#
3759# This is a monkey patch, to add control for exception management.
3760#
3761vpy_main = main
3762vpy_main.raise_exceptions=False
3763def main():
3764    if sys.platform != 'win32':
3765        if os.environ.get('TMPDIR','') == '.':
3766            os.environ['TMPDIR'] = '/tmp'
3767        elif os.environ.get('TEMPDIR','') == '.':
3768            os.environ['TEMPDIR'] = '/tmp'
3769    try:
3770        vpy_main()
3771    except Exception, err:
3772        if vpy_main.raise_exceptions:
3773            raise
3774        print ""
3775        print "ERROR:",str(err)
3776
3777#
3778# This is a monkey patch, to control the execution of the install_setuptools()
3779# function that is defined by virtualenv.
3780#
3781default_install_setuptools = install_setuptools
3782
3783def install_setuptools(py_executable, unzip=False):
3784    try:
3785        if install_setuptools.use_default:
3786            default_install_setuptools(py_executable, unzip)
3787    except OSError, err:
3788        print "-----------------------------------------------------------------"
3789        print "Error installing the 'setuptools' package!"
3790        if os.environ['HTTP_PROXY'] == '':
3791            print ""
3792            print "WARNING: you may need to set your HTTP_PROXY environment variable!"
3793        print "-----------------------------------------------------------------"
3794        sys.exit(0)
3795
3796install_setuptools.use_default=True
3797
3798
3799#
3800# This is a monkey patch, to control the execution of the install_pip()
3801# function that is defined by virtualenv.
3802#
3803default_install_pip = install_pip
3804
3805def install_pip(*args, **kwds):
3806    try:
3807        if install_pip.use_default:
3808            default_install_pip(*args, **kwds)
3809    except OSError, err:
3810        print "-----------------------------------------------------------------"
3811        print "Error installing the 'pip' package!"
3812        if os.environ['HTTP_PROXY'] == '':
3813            print ""
3814            print "WARNING: you may need to set your HTTP_PROXY environment variable!"
3815        print "-----------------------------------------------------------------"
3816        sys.exit(0)
3817
3818install_pip.use_default=True
3819
3820
3821#
3822# The following methods will be called by virtualenv
3823#
3824def extend_parser(parser):
3825    installer = get_installer()
3826    installer.modify_parser(parser)
3827
3828def adjust_options(options, args):
3829    installer = get_installer()
3830    installer.get_homedir(options, args)
3831    installer.adjust_options(options, args)
3832    installer.setup_installer(options)
3833   
3834def after_install(options, home_dir):
3835    installer = get_installer()
3836    installer.install_packages(options)
3837
3838
3839
3840#
3841# Imported from coopr.py
3842#
3843
3844#  _________________________________________________________________________
3845#
3846#  Coopr: A COmmon Optimization Python Repository
3847#  Copyright (c) 2008 Sandia Corporation.
3848#  This software is distributed under the BSD License.
3849#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
3850#  the U.S. Government retains certain rights in this software.
3851#  _________________________________________________________________________
3852
3853import sys
3854
3855class CooprInstaller(Installer):
3856
3857    def __init__(self):
3858        Installer.__init__(self)
3859        self.default_dirname='coopr'
3860        self.config_file='https://software.sandia.gov/svn/public/coopr/vpy/installer.ini'
3861
3862    def modify_parser(self, parser):
3863        Installer.modify_parser(self, parser)
3864
3865        parser.add_option('--coin',
3866            help='Use one or more packages from the Coin Bazaar software repository.  Multiple packages are specified with a comma-separated list.',
3867            action='store',
3868            dest='coin',
3869            default=None)
3870
3871    def get_other_packages(self, options):
3872        if options.coin is None:
3873            return
3874        for pkg in options.coin.split(','):
3875            if pkg is '':
3876                continue
3877            self.add_repository('coopr.'+pkg, root='https://projects.coin-or.org/svn/CoinBazaar/projects/coopr.'+pkg, dev=True, username=os.environ.get('COINOR_USERNAME',None))
3878
3879    def install_packages(self, options):
3880        Installer.install_packages(self, options)
3881        if sys.version_info[:2] < (2,5):
3882            print ""
3883            print "-----------------------------------------------------------------"
3884            print " WARNING: Most Coopr packages will only work with Python 2.5 or"
3885            print "          newer.  You have installed Coopr with:"
3886            print sys.version
3887            print "-----------------------------------------------------------------"
3888
3889            print ""
3890
3891def create_installer():
3892    return CooprInstaller()
3893
3894
3895##file site.py
3896SITE_PY = """
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
4027yBXo8FFND74JkgILcmKn2vJbYxD8H2/QG9E=
4028""".decode("base64").decode("zlib")
4029
4030##file ez_setup.py
4031EZ_SETUP_PY = """
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
4098178BYnMUkw==
4099""".decode("base64").decode("zlib")
4100
4101##file distribute_setup.py
4102DISTRIBUTE_SETUP_PY = """
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
4180""".decode("base64").decode("zlib")
4181
4182##file activate.sh
4183ACTIVATE_SH = """
4184eJytVFFv2jAQfs+vuIU+QDWK+tqKB6oigdRC1bBOW1sZk1yIpWAj2yGj0/77ziFAUijStPIA2Hc+
4185f/7u+64Bk0QYiEWKsMiMhRlCZjCCXNgEfKMyHSLMhOzw0IoVt+jDeazVAmbcJOdeA9Yqg5BLqSzo
4186TIKwEAmNoU3Xnhfh9hQ0W/DbA/o0QKNBCyqNAOVKaCUXKC2suBZ8lqIpskQMz9CW4J+x8d0texo+
4187Tr717thDbzLw4RWuwSYoi0z3cdvdY6m7DPy1VNoWibu9TDocB4eKeCxOwvgxGYxHg/F9/xiYXfAA
41880v7YAbBd6CS8ehaBLCktmmgSlRGpEVqiv+gPcBnBm0m+Qp6IMIGErxA4/VAoVIuFC9uE26L1ZSkS
4189QMjTlCRgFcwJAXWU/sVKu8WSk0bKo+YC4DvJRGW2DFsh52WZWqIjCM4cuRAmXM7RQE5645H7WoPT
4190Dl1LulgScozeUX/TC6jpbbVZ/QwG7Kn/GAzHoyPkF09r6xo9HzUxuDzWveDyoG2UeNCv4PJko8rw
4191FsImZRvtj572wL4QLgLSBV8qGaGxOnOewXfYGhBgGsM24cu729sutDXb9uo/HvlzExdaY0rdrxmt
4192Ys/63Z5Xgdr1GassGfO9koTqe7wDHxGNGw+Wi0p2h7Gb4YiNevd9xq7KtKpFd7j3inds0Q5FrBN7
4193LtIUYi5St1/NMi7LKdZpDhdLuwZ6FwkTmhsTUMaMR2SNdc7XLaoXFrahqQdTqtUs6Myu4YoUu6vb
4194guspCFm4ytsL6sNB8IFtu7UjFWlUnO00s7nhDWqssdth0Lu567OHx/H9w+TkjYWKd8ItyvlTAo+S
4195LxBeanVf/GmhP+rsoR8a4EwpeEpTgRgin0OPdiQZdy7CctYrLcq5XR5BhMTa5VWnk+f5xRtasvrq
4196gsZBx6jY5lxjh7sqnbrvnisQp1T6KNiX6fQV9m/D1GC9SvPEQ1v7g+WIrxjaMf9Js/QT5uh/ztB/
4197n5/b2Uk0/AXm/2MV
4198""".decode("base64").decode("zlib")
4199
4200##file activate.bat
4201ACTIVATE_BAT = """
4202eJyFUssKgzAQvAfyD3swYH+hItSiVKlGsalQKOyhauvFHOr/U+MzFcWc9jEzO7vkVLw+EmRZUvIt
4203GsiCVNydED2e2YhahkgJJVUJtWwgL8qqLnJI0jhKBJiUQPsUv6/YRmJcKDkMlBGOcehOmptctgJj
4204e2IP4cfcjyNvFOwVp/JSdWqMygq+MthmkwHNojmfhjuRh3iAGffncsPYhpl2mm5sbY+9QzjC7ylt
4205sFy6LTEL3rKRcLsGicrXV++4HVz1jzN4Vta+BnsingM+nMLSiB53KfkBsnmnEA==
4206""".decode("base64").decode("zlib")
4207
4208##file deactivate.bat
4209DEACTIVATE_BAT = """
4210eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
4211FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL
4212i2dASrm4rFz9XLgAwJNbyQ==
4213""".decode("base64").decode("zlib")
4214
4215##file distutils-init.py
4216DISTUTILS_INIT = """
4217eJytVl2L6zYQffevGBKK7XavKe3bhVBo78uFSyml0IdlEVpbTtR1JCMpm6S/vjOSY0v+uO1DDbs4
42180tF8nJk5sjz32jjQNpPhzd7H1ys3SqqjhcfCL1q18vgbN1YY2Kc/pQWlHXB4l8ZdeCfUO5x1c+nE
4219E1gNVwE1V3CxAqQDp6GVqgF3EmBd08nXLGukUfws4IDBVD13p2pYoS3rLk52ltF6hPhLS1XM4EUc
4220VsVYKzvBWPkE+WgmLzPZjkaUNmd6KVI3JRwWoRSLM6P98mMG+Dw4q+il8Ev07P7ATCNmRlfQ8/qN
4221HwVwB99Y4H0vMHAi6BWZUoEhoqXTNXdSK+A2LN6tE+fJ0E+7MhOdFSEM5lNgrJIKWXDF908wy87D
4222xE3UoHsxkegZTaHIHGNSSYfm+ntelpURvCnK7NEWBI/ap/b8Z1m232N2rj7B60V2DRM3B5NpaLSw
4223KnfwpvQVTviHOR+F88lhQyBAGlE7be6DoRNg9ldsG3218IHa6MRNU+tGBEYIggwafRk6yzsXDcVU
42249Ua08kYxt+F3x12LRaQi52j0xx/ywFxrdMRqVevzmaummlIYEp0WsCAaX8cFb6buuLUTqEgQQ6/Q
422504iWRoF38m/BdE8VtlBY0bURiB6KG1crpMZwc2fIjqWh+1UrkSLpWUIP8PySwLKv4qPGSVqDuMPy
4226dywQ+gS7L1irXVkm5pJsq3l+Ib1lMOvUrxI+/mBBY4KB+WpUtcO06RtzckNvQ6vYj1lGoZM2sdDG
4227fryJPYJVn/Cfka8XSqNaoLKhmOlqXMzW9+YBVp1EtIThZtOwzCRvMaARa+0xD0b2kcaJGwJsMbc7
4228hLUfY4vKvsCOBdvDnyfuRbzmXRdGTZgPF7oGQkJACWVD22IMQdhx0npt5S2f+pXO+OwH6d+hwiS5
42297IJOjcK2emj1zBy1aONHByfAMoraw6WlrSIFTbGghqASoRCjVncYROFpXM4uYSqhGnuVeGvks4jz
4230cjnCoR5GnPW7KOh4maVbdFeoplgJ3wh3MSrAsv/QuMjOspnTKRl1fTYqqNisv7uTVnhF1GhoBFbp
4231lh+OcXN2riA5ZrYXtWxlfcDuC8U5kLoN3CCJYXGpesO6dx6rU0zGMtjU6cNlmW0Fid8Sja4ZG+Z3
4232fTPbyj+mZnZ2wSQK8RaT9Km0ySRuLpm0DkUUL0ra3WQ2BgGJ7v9I9SKqNKZ/IR4R28RHm+vEz5ic
4233nZ2IH7bfub8pU1PR3gr10W7xLTfHh6Z6bgZ7K14G7Mj/1z5J6MFo6V5e07H0Ou78dTyeI+mxKOpI
4234eC2KMSj6HKxd6Uudf/n886fPv+f++x1lbASlmjQuPz8OvGA0j7j2eCu/4bcW6SFeCuNJ0W1GQHI5
4235iwC9Ey0bjtHd9P4dPA++XxLnZDVuxvFEtlm3lf5a2c02u2LRYXHH/AOs8pIa
4236""".decode("base64").decode("zlib")
4237
4238##file distutils.cfg
4239DISTUTILS_CFG = """
4240eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
4241xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
42429FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
4243""".decode("base64").decode("zlib")
4244
4245##file activate_this.py
4246ACTIVATE_THIS = """
4247eJyNUk2L3DAMvftXiCxLEphmSvc2MIcu9NaWHnopwxCcRNlRN7GD7clM/n0lp5mPZQs1JLb8pKcn
4248WUmSPE9w9GReAM9Yt9RhFg7kSzmtoKE6ZGU0ynJ7AfIcJnuEE3Wd0nWgUQcEQWEkF466QzMCf+Ss
42496dGEQqmfgtbaQIWcDxs4HdBElv7og1wBg3gmH0TMjykcrAEyAd3gkP8rMDaocMDbHBWZ9RBdVZIk
4250SgU3bRTwWjQrPNc4BPiue/zinHUz7DRxws/eowtkTUSyiMhKfi2y3NHMdXX0itcOpYMOh3Ww61g8
4251luJSDFP6tmH3ftyki2eeJ7mifrAugJ/8crReqUqztC0fC4kuGnKGxWf/snXlZb8kzXMmboW0GDod
4252Wut62G4hPZF5+pTO5XtiKYOuX/UL+ptcvy2ZTPKvIP1KFdeTiuuHxTXNFXYe/5+km0nmJ3r0KTxG
4253YSM6z23fbZ7276Tg9x5LdiuFjok7noks1sP2tWscpeRX6KaRnRuT3WnKlQQ51F3JlC2dmSvSRENd
4254j3wvetUDfLOjDDLPYtPwjDJb7yHYeNXyMPMLtdEQKRtl8HQrdLdX3O4YxZP7RvfcNH6ZCPMsi8td
4255qZvLAN7yFnoY0DSZhOUXj4WWy+tZ8190ud1tPu5Zzy2N+gOGaVfA
4256""".decode("base64").decode("zlib")
4257
4258if __name__ == '__main__':
4259    main()
4260
4261# pyutilib.virtualenv: ignoring comment
4262## Copy python.exe.manifest
4263## Monkeypatch distutils.sysconfig
Note: See TracBrowser for help on using the repository browser.