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

Last change on this file since 2759 was 2759, checked in by wehart, 9 years ago

Update due to changes in pyutilib.virtualenv 1.5

  • 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    return svndir+"/"+latest_str
2727
2728
2729
2730def zip_file(filename,fdlist):
2731    zf = zipfile.ZipFile(filename, 'w')
2732    for file in fdlist:
2733        if os.path.isdir(file):
2734            for root, dirs, files in os.walk(file):
2735                for fname in files:
2736                    if fname.endswith('exe'):
2737                        zf.external_attr = (0777 << 16L) | (010 << 28L)
2738                    else:
2739                        zf.external_attr = (0660 << 16L) | (010 << 28L)
2740                    zf.write(join(root,fname))
2741        else:
2742            zf.write(file)
2743    zf.close()
2744
2745
2746def unzip_file(filename, dir=None):
2747    fname = os.path.abspath(filename)
2748    zf = zipfile.ZipFile(fname, 'r')
2749    if dir is None:
2750        dir = os.getcwd()
2751    for file in zf.infolist():
2752        name = file.filename
2753        if name.endswith('/') or name.endswith('\\'):
2754            outfile = os.path.join(dir, name)
2755            if not os.path.exists(outfile):
2756                os.makedirs(outfile)
2757        else:
2758            outfile = os.path.join(dir, name)
2759            parent = os.path.dirname(outfile)
2760            if not os.path.exists(parent):
2761                os.makedirs(parent)
2762            OUTPUT = open(outfile, 'wb')
2763            OUTPUT.write(zf.read(name))
2764            OUTPUT.close()
2765    zf.close()
2766
2767
2768
2769class Repository(object):
2770
2771    svn_get='checkout'
2772    easy_install_path = ["easy_install"]
2773    python = "python"
2774    svn = "svn"
2775    dev = []
2776
2777    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):
2778        class _TEMP_(object): pass
2779        self.config = _TEMP_()
2780        self.config.name=name
2781        self.config.root=root
2782        self.config.trunk=trunk
2783        self.config.stable=stable
2784        self.config.release=release
2785        self.config.tag=tag
2786        self.config.pyname=pyname
2787        self.config.pypi=pypi
2788        if dev == 'True' or dev is True:
2789            self.config.dev=True
2790        else:
2791            self.config.dev=False
2792        self.config.username=username
2793        if install == 'False' or install is False:
2794            self.config.install=False
2795        else:
2796            self.config.install=True
2797        self.config.rev=rev
2798        self.initialize(self.config)
2799
2800    def initialize(self, config):
2801        self.name = config.name
2802        self.root = config.root
2803        self.trunk = None
2804        self.trunk_root = None
2805        self.stable = None
2806        self.stable_root = None
2807        self.release = None
2808        self.tag = None
2809        self.release_root = None
2810        #
2811        self.pypi = config.pypi
2812        if not config.pypi is None:
2813            self.pyname=config.pypi
2814        else:
2815            self.pyname=config.pyname
2816        self.dev = config.dev
2817        if config.dev:
2818            Repository.dev.append(config.name)
2819        self.pkgdir = None
2820        self.pkgroot = None
2821        if config.username is None or '$' in config.username:
2822            self.svn_username = []
2823        else:
2824            self.svn_username = ['--username', config.username]
2825        if config.rev is None:
2826            self.rev=''
2827            self.revarg=[]
2828        else:
2829            self.rev='@'+config.rev
2830            self.revarg=['-r',config.rev]
2831        self.install = config.install
2832
2833    def guess_versions(self, offline=False):
2834        if not self.config.root is None:
2835            if using_subversion:
2836                rootdir_output = commands.getoutput('svn ls ' + self.config.root)
2837            else:
2838                if sys.version_info[:2] <= (2,5):
2839                    rootdir_output = urllib2.urlopen(self.config.root).read()
2840                else:
2841                    rootdir_output = urllib2.urlopen(self.config.root, timeout=30).read()
2842            try:
2843                self.trunk = self.config.root+'/trunk'
2844                self.trunk_root = self.trunk
2845            except urllib2.HTTPError:
2846                self.trunk = None
2847                self.trunk_root = None
2848            try:
2849                if offline or not 'stable' in rootdir_output:
2850                    raise IOError
2851                self.stable = guess_release(self.config.root+'/stable')
2852                self.stable_root = self.stable
2853            except (urllib2.HTTPError,IOError):
2854                self.stable = None
2855                self.stable_root = None
2856            try:
2857                if offline or not 'releases' in rootdir_output:
2858                    raise IOError
2859                self.release = guess_release(self.config.root+'/releases')
2860                self.tag = None
2861                self.release_root = self.release
2862            except (urllib2.HTTPError,IOError):
2863                try:
2864                    if offline or not 'tags' in rootdir_output:
2865                        raise IOError
2866                    self.release = guess_release(self.config.root+'/tags')
2867                    self.tag = self.release
2868                    self.release_root = self.release
2869                except (urllib2.HTTPError,IOError):
2870                    self.release = None
2871                    self.release_root = None
2872        if not self.config.trunk is None:
2873            if self.trunk is None:
2874                self.trunk = self.config.trunk
2875            else:
2876                self.trunk += self.config.trunk
2877        if not self.config.stable is None:
2878            if self.stable is None:
2879                self.stable = self.config.stable
2880            else:
2881                self.stable += self.config.stable
2882        if not self.config.release is None:
2883            if self.release is None:
2884                self.release = self.config.release
2885            else:
2886                self.release += self.config.release
2887        if not self.config.tag is None:
2888            if self.release is None:
2889                self.release = self.config.tag
2890            else:
2891                self.release += self.config.tag
2892
2893
2894    def write_config(self, OUTPUT):
2895        config = self.config
2896        print >>OUTPUT, '[%s]' % config.name
2897        if not config.root is None:
2898            print >>OUTPUT, 'root=%s' % config.root
2899        if not config.trunk is None:
2900            print >>OUTPUT, 'trunk=%s' % config.trunk
2901        if not config.stable is None:
2902            print >>OUTPUT, 'stable=%s' % config.stable
2903        if not config.tag is None:
2904            print >>OUTPUT, 'tag=%s' % config.tag
2905        elif not config.release is None:
2906            print >>OUTPUT, 'release=%s' % config.release
2907        if not config.pypi is None:
2908            print >>OUTPUT, 'pypi=%s' % config.pypi
2909        elif not config.pyname is None:
2910            print >>OUTPUT, 'pypi=%s' % config.pyname
2911        print >>OUTPUT, 'dev=%s' % str(config.dev)
2912        print >>OUTPUT, 'install=%s' % str(config.install)
2913        if not config.rev is None:
2914            print >>OUTPUT, 'rev=%s' % str(config.rev)
2915        if not config.username is None:
2916            print >>OUTPUT, 'username=%s' % str(config.username)
2917
2918
2919    def find_pkgroot(self, trunk=False, stable=False, release=False):
2920        if trunk:
2921            if self.trunk is None:
2922                if not self.stable is None:
2923                    self.find_pkgroot(stable=True)
2924                elif self.pypi is None:
2925                    self.find_pkgroot(release=True)
2926                else:
2927                    # use easy_install
2928                    self.pkgdir = None
2929                    self.pkgroot = None
2930                    return
2931            else:
2932                self.pkgdir = self.trunk
2933                self.pkgroot = self.trunk_root
2934                return
2935
2936        elif stable:
2937            if self.stable is None: 
2938                if not self.release is None:
2939                    self.find_pkgroot(release=True)
2940                elif self.pypi is None:
2941                    self.find_pkgroot(trunk=True)
2942                else:
2943                    # use easy_install
2944                    self.pkgdir = None
2945                    self.pkgroot = None
2946                    return
2947            else:
2948                self.pkgdir = self.stable
2949                self.pkgroot = self.stable_root
2950                return
2951
2952        elif release:
2953            if self.release is None:
2954                if not self.stable is None:
2955                    self.find_pkgroot(stable=True)
2956                elif self.pypi is None:
2957                    self.find_pkgroot(trunk=True)
2958                else:
2959                    # use easy_install
2960                    self.pkgdir = None
2961                    self.pkgroot = None
2962                    return
2963            else:
2964                self.pkgdir = self.release
2965                self.pkgroot = self.release_root
2966
2967        else:
2968            raise IOError, "Must have one of trunk, stable or release specified"
2969           
2970
2971    def install_trunk(self, dir=None, install=True, preinstall=False, offline=False):
2972        self.find_pkgroot(trunk=True)
2973        self.perform_install(dir=dir, install=install, preinstall=preinstall, offline=offline)
2974       
2975    def install_stable(self, dir=None, install=True, preinstall=False, offline=False):
2976        self.find_pkgroot(stable=True)
2977        self.perform_install(dir=dir, install=install, preinstall=preinstall, offline=offline)
2978       
2979    def install_release(self, dir=None, install=True, preinstall=False, offline=False):
2980        self.find_pkgroot(release=True)
2981        self.perform_install(dir=dir, install=install, preinstall=preinstall, offline=offline)
2982       
2983    def perform_install(self, dir=None, install=True, preinstall=False, offline=False):
2984        if self.pkgdir is None:
2985            self.easy_install(install, preinstall, dir, offline)
2986            return
2987        print "-----------------------------------------------------------------"
2988        print "  Installing branch"
2989        print "  Checking out source for package",self.name
2990        print "     Subversion dir: "+self.pkgdir
2991        if os.path.exists(dir):
2992            print "     No checkout required"
2993            print "-----------------------------------------------------------------"
2994        else:
2995            print "-----------------------------------------------------------------"
2996            self.run([self.svn]+self.svn_username+[Repository.svn_get,'-q',self.pkgdir+self.rev, dir])
2997        if install:
2998            if self.dev:
2999                self.run([self.python, 'setup.py', 'develop'], dir=dir)
3000            else:
3001                self.run([self.python, 'setup.py', 'install'], dir=dir)
3002
3003    def update_trunk(self, dir=None):
3004        self.find_pkgroot(trunk=True)
3005        self.perform_update(dir=dir)
3006
3007    def update_stable(self, dir=None):
3008        self.find_pkgroot(stable=True)
3009        self.perform_update(dir=dir)
3010
3011    def update_release(self, dir=None):
3012        self.find_pkgroot(release=True)
3013        self.perform_update(dir=dir)
3014
3015    def perform_update(self, dir=None):
3016        if self.pkgdir is None:
3017            self.easy_upgrade()
3018            return
3019        print "-----------------------------------------------------------------"
3020        print "  Updating branch"
3021        print "  Updating source for package",self.name
3022        print "     Subversion dir: "+self.pkgdir
3023        print "     Source dir:     "+dir
3024        print "-----------------------------------------------------------------"
3025        self.run([self.svn,'update','-q']+self.revarg+[dir])
3026        if self.dev:
3027            self.run([self.python, 'setup.py', 'develop'], dir=dir)
3028        else:
3029            self.run([self.python, 'setup.py', 'install'], dir=dir)
3030
3031    def Xsdist_trunk(self, format='zip'):
3032        if self.trunk is None:
3033            if not self.pypi is None:
3034                self.easy_install()
3035            elif not self.stable is None:
3036                self.sdist_stable(format=format)
3037            else:
3038                self.sdist_release(format=format)
3039        else:
3040            self.pkgdir=self.trunk
3041            self.pkgroot=self.trunk_root
3042            print "-----------------------------------------------------------------"
3043            print "  Checking out source for package",self.name
3044            print "     Subversion dir: "+self.trunk
3045            print "-----------------------------------------------------------------"
3046            self.run([self.svn]+self.svn_username+[Repository.svn_get,'-q',self.trunk, 'pkg'+self.name+self.rev])
3047            self.run([self.python, 'setup.py', 'sdist','-q','--dist-dir=..', '--formats='+format], dir='pkg'+self.name)
3048            os.chdir('..')
3049            rmtree('pkg'+self.name)
3050
3051    def Xsdist_stable(self, format='zip'):
3052        if self.stable is None:
3053            if not self.pypi is None:
3054                self.easy_install()
3055            elif not self.release is None:
3056                self.install_release()
3057            elif not self.trunk is None:
3058                self.install_trunk()
3059        else:
3060            self.pkgdir=self.stable
3061            self.pkgroot=self.stable_root
3062            print "-----------------------------------------------------------------"
3063            print "  Checking out source for package",self.name
3064            print "     Subversion dir: "+self.stable
3065            print "     Source dir:     "+dir
3066            print "-----------------------------------------------------------------"
3067            self.run([self.svn]+self.svn_username+[Repository.svn_get,'-q',self.stable, dir])
3068            self.run([self.python, 'setup.py', 'develop'], dir=dir)
3069
3070    def Xsdist_release(self, dir=None):
3071        if self.release is None:
3072            if not self.pypi is None:
3073                self.easy_install()
3074            elif not self.stable is None:
3075                self.install_stable()
3076            elif not self.trunk is None:
3077                self.install_trunk()
3078        else:
3079            self.pkgdir=self.release
3080            self.pkgroot=self.release_root
3081            print "-----------------------------------------------------------------"
3082            print "  Checking out source for package",self.name
3083            print "     Subversion dir: "+self.release
3084            print "     Source dir:     "+dir
3085            print "-----------------------------------------------------------------"
3086            self.run([self.svn]+self.svn_username+[Repository.svn_get]+self.rev+['-q',self.release, dir])
3087            self.run([self.python, 'setup.py', 'install'], dir=dir)
3088
3089    def easy_install(self, install, preinstall, dir, offline):
3090        try:
3091            if install:
3092                #self.run([self.easy_install_path, '-q', self.pypi])
3093                if offline:
3094                    self.run([self.python, 'setup.py', 'install'], dir=dir)
3095                else:
3096                    self.run(self.easy_install_path + ['-q', self.pypi])
3097            elif preinstall: 
3098                if not os.path.exists(dir):
3099                    self.run(self.easy_install_path + ['-q', '--editable', '--build-directory', '.', self.pypi], dir=os.path.dirname(dir))
3100        except OSError, err:
3101            print "-----------------------------------------------------------------"
3102            print "Warning!!! Ignoring easy_install error '%s'" % str(err)
3103            print "-----------------------------------------------------------------"
3104
3105    def easy_upgrade(self):
3106        self.run(self.easy_install_path + ['-q', '--upgrade', self.pypi])
3107
3108    def run(self, cmd, dir=None):
3109        cwd=os.getcwd()
3110        if not dir is None:
3111            os.chdir(dir)
3112            cwd=dir
3113        print "Running command '%s' in directory %s" % (" ".join(cmd), cwd)
3114        call_subprocess(cmd, filter_stdout=filter_python_develop, show_stdout=True)
3115        if not dir is None:
3116            os.chdir(cwd)
3117
3118
3119if sys.platform.startswith('win'):
3120    if not is_jython:
3121        Repository.python += '.exe'
3122    Repository.svn += '.exe'
3123
3124
3125def filter_python_develop(line):
3126    if not line.strip():
3127        return Logger.DEBUG
3128    for prefix in ['Searching for', 'Reading ', 'Best match: ', 'Processing ',
3129                   'Moving ', 'Adding ', 'running ', 'writing ', 'Creating ',
3130                   'creating ', 'Copying ']:
3131        if line.startswith(prefix):
3132            return Logger.DEBUG
3133    return Logger.NOTIFY
3134
3135
3136def apply_template(str, d):
3137    t = string.Template(str)
3138    return t.safe_substitute(d)
3139
3140
3141wrapper = textwrap.TextWrapper(subsequent_indent="    ")
3142
3143
3144class Installer(object):
3145
3146    def __init__(self):
3147        self.description="This script manages the installation of packages into a virtual Python installation."
3148        self.home_dir = None
3149        self.default_dirname='python'
3150        self.abshome_dir = None
3151        self.sw_packages = []
3152        self.sw_dict = {}
3153        self.cmd_files = []
3154        self.auxdir = []
3155        self.config=None
3156        self.config_file=None
3157        self.README="""
3158#
3159# Virtual Python installation generated by the %s script.
3160#
3161# This directory is managed with virtualenv, which creates a
3162# virtual Python installation.  If the 'bin' directory is put in
3163# user's PATH environment, then the bin/python command can be used
3164# without further installation.
3165#
3166# Directories:
3167#   admin      Administrative data for maintaining this distribution
3168#   bin        Scripts and executables
3169#   dist       Python packages that are not intended for development
3170#   include    Python header files
3171#   lib        Python libraries and installed packages
3172#   src        Python packages whose source files can be
3173#              modified and used directly within this virtual Python
3174#              installation.
3175#   Scripts    Python bin directory (used on MS Windows)
3176#
3177""" % sys.argv[0]
3178
3179    def add_repository(self, *args, **kwds):
3180        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:
3181            raise IOError, "No repository info specified for repository "+args[0]
3182        repos = Repository( *args, **kwds)
3183        self.sw_dict[repos.name] = repos
3184        self.sw_packages.append( repos )
3185
3186    def add_dos_cmd(self, file):
3187        self.cmd_files.append( file )
3188
3189    def add_auxdir(self, package, todir, fromdir):
3190        self.auxdir.append( (todir, package, fromdir) )
3191
3192    def modify_parser(self, parser):
3193        self.default_windir = 'C:\\'+self.default_dirname
3194        self.default_unixdir = './'+self.default_dirname
3195        #
3196        parser.add_option('--debug',
3197            help='Configure script to generate debugging IO and to raise exceptions.',
3198            action='store_true',
3199            dest='debug',
3200            default=False)
3201
3202        parser.add_option('--trunk',
3203            help='Install trunk branches of Python software.',
3204            action='store_true',
3205            dest='trunk',
3206            default=False)
3207
3208        parser.add_option('--stable',
3209            help='Install stable branches of Python software.',
3210            action='store_true',
3211            dest='stable',
3212            default=False)
3213
3214        parser.add_option('--update',
3215            help='Update all Python packages.',
3216            action='store_true',
3217            dest='update',
3218            default=False)
3219
3220        parser.add_option('--proxy',
3221            help='Set the HTTP_PROXY environment with this option.',
3222            action='store',
3223            dest='proxy',
3224            default=None)
3225
3226        parser.add_option('--preinstall',
3227            help='Prepare an installation that will be used to build a MS Windows installer.',
3228            action='store_true',
3229            dest='preinstall',
3230            default=False)
3231
3232        parser.add_option('--offline',
3233            help='Perform installation offline, using source extracted from ZIP files.',
3234            action='store_true',
3235            dest='offline',
3236            default=False)
3237
3238        parser.add_option('--zip',
3239            help='Add ZIP files that are use define this installation.',
3240            action='append',
3241            dest='zip',
3242            default=[])
3243
3244        parser.add_option('--use-pythonpath',
3245            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.",
3246            action='store_true',
3247            dest='use_pythonpath',
3248            default=False)
3249
3250        parser.add_option(
3251            '--site-packages',
3252            dest='no_site_packages',
3253            action='store_false',
3254            help="Setup the virtual environment to use the global site-packages",
3255            default=True)
3256
3257        parser.add_option('--config',
3258            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.',
3259            action='append',
3260            dest='config_files',
3261            default=[])
3262
3263        parser.add_option('--keep-config',
3264            help='Keep the initial configuration data that was specified if the --config option is specified.',
3265            action='store_true',
3266            dest='keep_config',
3267            default=False)
3268
3269        parser.add_option('--localize',
3270            help='Force localization of DOS scripts on Linux platforms',
3271            action='store_true',
3272            dest='localize',
3273            default=False)
3274
3275        #
3276        # Change the virtualenv options
3277        #
3278        parser.remove_option("--python")
3279        parser.add_option("--python",
3280            dest='python',
3281            metavar='PYTHON_EXE',
3282            help="Specify the Python interpreter to use, e.g., --python=python2.5 will install with the python2.5 interpreter.")
3283        parser.remove_option("--relocatable")
3284        parser.remove_option("--version")
3285        parser.remove_option("--unzip-setuptools")
3286        parser.remove_option("--no-site-packages")
3287        parser.remove_option("--clear")
3288        #
3289        # Add description
3290        #
3291        parser.description=self.description
3292        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>'."
3293       
3294
3295    def adjust_options(self, options, args):
3296        #
3297        # Force options.clear to be False.  This allows us to preserve the logic
3298        # associated with --clear, which we may want to use later.
3299        #
3300        options.clear=False
3301        #
3302        global vpy_main
3303        if options.debug:
3304            vpy_main.raise_exceptions=True
3305        #
3306        global logger
3307        verbosity = options.verbose - options.quiet
3308        self.logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
3309        logger = self.logger
3310        #
3311        if options.update and (options.stable or options.trunk):
3312            self.logger.fatal("ERROR: cannot specify --stable or --trunk when specifying the --update option.")
3313            sys.exit(1000)
3314        if options.update and len(options.config_files) > 0:
3315            self.logger.fatal("ERROR: cannot specify --config when specifying the --update option.")
3316            sys.exit(1000)
3317        if options.update and options.keep_config:
3318            self.logger.fatal("ERROR: cannot specify --keep-config when specifying the --update option.")
3319            sys.exit(1000)
3320        if len(args) > 1:
3321            self.logger.fatal("ERROR: installer script can only have one argument")
3322            sys.exit(1000)
3323        #
3324        # Error checking
3325        #
3326        if not options.preinstall and (os.path.exists(self.abshome_dir) ^ options.update):
3327            if options.update:
3328                self.logger.fatal(wrapper.fill("ERROR: The 'update' option is specified, but the installation path '%s' does not exist!" % self.home_dir))
3329                sys.exit(1000)
3330            elif os.path.exists(join(self.abshome_dir,'bin')):
3331                    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))
3332                    sys.exit(1000)
3333        if len(args) == 0:
3334            args.append(self.abshome_dir)
3335        #
3336        # Parse config files
3337        #
3338        if options.update:
3339            self.config=None
3340            options.config_files.append( join(self.abshome_dir, 'admin', 'config.ini') )
3341        if not self.config is None and (len(options.config_files) == 0 or options.keep_config):
3342            fp = StringIO.StringIO(self.config)
3343            self.read_config_file(fp=fp)
3344            fp.close()
3345        if not self.config_file is None and (len(options.config_files) == 0 or options.keep_config):
3346            self.read_config_file(file=self.config_file)
3347        for file in options.config_files:
3348            self.read_config_file(file=file)
3349        print "-----------------------------------------------------------------"
3350        print "Finished processing configuration information."
3351        print "-----------------------------------------------------------------"
3352        print " START - Configuration summary"
3353        print "-----------------------------------------------------------------"
3354        self.write_config(stream=sys.stdout)
3355        print "-----------------------------------------------------------------"
3356        print " END - Configuration summary"
3357        print "-----------------------------------------------------------------"
3358        #
3359        # If applying preinstall, then only do subversion exports
3360        #
3361        if options.preinstall:
3362            Repository.svn_get='export'
3363
3364    def get_homedir(self, options, args):
3365        #
3366        # Figure out the installation directory
3367        #
3368        if len(args) == 0:
3369            path = self.guess_path()
3370            if path is None or options.preinstall:
3371                # Install in a default location.
3372                if sys.platform == 'win32':
3373                    home_dir = self.default_windir
3374                else:
3375                    home_dir = self.default_unixdir
3376            else:
3377                home_dir = os.path.dirname(os.path.dirname(path))
3378        else:
3379            home_dir = args[0]
3380        self.home_dir = home_dir
3381        self.abshome_dir = os.path.abspath(home_dir)
3382
3383    def guess_path(self):
3384        return None
3385
3386    def setup_installer(self, options):
3387        if options.preinstall:
3388            print "Creating preinstall zip file in '%s'" % self.home_dir
3389        elif options.update:
3390            print "Updating existing installation in '%s'" % self.home_dir
3391        else:
3392            print "Starting fresh installation in '%s'" % self.home_dir
3393        #
3394        # Setup HTTP proxy
3395        #
3396        if options.offline:
3397            os.environ['HTTP_PROXY'] = ''
3398            os.environ['http_proxy'] = ''
3399        else:
3400            proxy = ''
3401            if not options.proxy is None:
3402                proxy = options.proxy
3403            if proxy is '':
3404                proxy = os.environ.get('HTTP_PROXY', '')
3405            if proxy is '':
3406                proxy = os.environ.get('http_proxy', '')
3407            os.environ['HTTP_PROXY'] = proxy
3408            os.environ['http_proxy'] = proxy
3409            print "  using the HTTP_PROXY environment: %s" % proxy
3410            print ""
3411        #
3412        # Disable the PYTHONPATH, to isolate this installation from
3413        # other Python installations that a user may be working with.
3414        #
3415        if not options.use_pythonpath:
3416            try:
3417                del os.environ["PYTHONPATH"]
3418            except:
3419                pass
3420        #
3421        # If --preinstall is declared, then we remove the directory, and prepare a ZIP file
3422        # that contains the full installation.
3423        #
3424        if options.preinstall:
3425            print "-----------------------------------------------------------------"
3426            print " STARTING preinstall in directory %s" % self.home_dir
3427            print "-----------------------------------------------------------------"
3428            rmtree(self.abshome_dir)
3429            os.mkdir(self.abshome_dir)
3430        #
3431        # When preinstalling or working offline, disable the
3432        # default install_setuptools() function.
3433        #
3434        if options.offline:
3435            install_setuptools.use_default=False
3436            install_pip.use_default=False
3437        #
3438        # If we're clearing the current installation, then remove a bunch of
3439        # directories
3440        #
3441        elif options.clear:
3442            path = join(self.abshome_dir,'src')
3443            if os.path.exists(path):
3444                rmtree(path)
3445        #
3446        # Open up zip files
3447        #
3448        for file in options.zip:
3449            unzip_file(file, dir=self.abshome_dir)
3450
3451        if options.preinstall or not options.offline:
3452            #self.get_packages(options)
3453            pass
3454        else:
3455            self.sw_packages.insert( 0, Repository('virtualenv', pypi='virtualenv') )
3456            self.sw_packages.insert( 0, Repository('pip', pypi='pip') )
3457            self.sw_packages.insert( 0, Repository('setuptools', pypi='setuptools') )
3458            #
3459            # Configure the package versions, for offline installs
3460            #
3461            for pkg in self.sw_packages:
3462                pkg.guess_versions(True)
3463
3464    def get_packages(self, options):
3465        #
3466        # Setup the 'admin' directory
3467        #
3468        if not os.path.exists(self.abshome_dir):
3469            os.mkdir(self.abshome_dir)
3470        if not os.path.exists(join(self.abshome_dir,'admin')):
3471            os.mkdir(join(self.abshome_dir,'admin'))
3472        if options.update:
3473            INPUT=open(join(self.abshome_dir,'admin',"virtualenv.cfg"),'r')
3474            options.trunk = INPUT.readline().strip() != 'False'
3475            options.stable = INPUT.readline().strip() != 'False'
3476            INPUT.close()
3477        else:
3478            OUTPUT=open(join(self.abshome_dir,'admin',"virtualenv.cfg"),'w')
3479            print >>OUTPUT, options.trunk
3480            print >>OUTPUT, options.stable
3481            OUTPUT.close()
3482            self.write_config( join(self.abshome_dir,'admin','config.ini') )
3483        #
3484        # Setup package directories
3485        #
3486        if not os.path.exists(join(self.abshome_dir,'dist')):
3487            os.mkdir(join(self.abshome_dir,'dist'))
3488        if not os.path.exists(self.abshome_dir+os.sep+"src"):
3489            os.mkdir(self.abshome_dir+os.sep+"src")
3490        if not os.path.exists(self.abshome_dir+os.sep+"bin"):
3491            os.mkdir(self.abshome_dir+os.sep+"bin")
3492        #
3493        # Get source packages
3494        #
3495        self.sw_packages.insert( 0, Repository('virtualenv', pypi='virtualenv') )
3496        self.sw_packages.insert( 0, Repository('pip', pypi='pip') )
3497        if options.preinstall:
3498            #
3499            # When preinstalling, add the setuptools package to the installation list
3500            #
3501            self.sw_packages.insert( 0, Repository('setuptools', pypi='setuptools') )
3502        #
3503        # Add Coopr Forum packages
3504        #
3505        self.get_other_packages(options)
3506        #
3507        # Get package source
3508        #
3509        for pkg in self.sw_packages:
3510            pkg.guess_versions(False)
3511            if not pkg.install:
3512                pkg.find_pkgroot(trunk=options.trunk, stable=options.stable, release=not (options.trunk or options.stable))
3513                continue
3514            if pkg.dev:
3515                tmp = join(self.abshome_dir,'src',pkg.name)
3516            else:
3517                tmp = join(self.abshome_dir,'dist',pkg.name)
3518            if options.trunk:
3519                if not options.update:
3520                    pkg.install_trunk(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3521            elif options.stable:
3522                if not options.update:
3523                    pkg.install_stable(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3524            else:
3525                if not options.update:
3526                    pkg.install_release(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3527        if options.update or not os.path.exists(join(self.abshome_dir,'doc')):
3528            self.install_auxdirs(options)
3529        #
3530        # Create a README.txt file
3531        #
3532        OUTPUT=open(join(self.abshome_dir,"README.txt"),"w")
3533        print >>OUTPUT, self.README.strip()
3534        OUTPUT.close()
3535        #
3536        # Finalize preinstall
3537        #
3538        if options.preinstall:
3539            print "-----------------------------------------------------------------"
3540            print " FINISHED preinstall in directory %s" % self.home_dir
3541            print "-----------------------------------------------------------------"
3542            os.chdir(self.abshome_dir)
3543            zip_file(self.default_dirname+'.zip', ['.'])
3544            sys.exit(0)
3545
3546    def get_other_packages(self, options):
3547        #
3548        # Used by subclasses of Installer to
3549        # add packages that were requested through other means....
3550        #
3551        pass
3552       
3553    def install_packages(self, options):
3554        #
3555        # Set the bin directory
3556        #
3557        if os.path.exists(self.abshome_dir+os.sep+"Scripts"):
3558            bindir = join(self.abshome_dir,"Scripts")
3559        else:
3560            bindir = join(self.abshome_dir,"bin")
3561        if is_jython:
3562            Repository.python = os.path.abspath(join(bindir, 'jython.bat'))
3563        else:
3564            Repository.python = os.path.abspath(join(bindir, 'python'))
3565        if os.path.exists(os.path.abspath(join(bindir, 'easy_install'))):
3566            Repository.easy_install_path = [Repository.python, os.path.abspath(join(bindir, 'easy_install'))]
3567        else:
3568            Repository.easy_install_path = [os.path.abspath(join(bindir, 'easy_install.exe'))]
3569        #
3570        if options.preinstall or not options.offline:
3571            self.get_packages(options)
3572        #
3573        # Install the related packages
3574        #
3575        for pkg in self.sw_packages:
3576            if not pkg.install:
3577                pkg.find_pkgroot(trunk=options.trunk, stable=options.stable, release=not (options.trunk or options.stable))
3578                continue
3579            if pkg.dev:
3580                srcdir = join(self.abshome_dir,'src',pkg.name)
3581            else:
3582                srcdir = join(self.abshome_dir,'dist',pkg.name)
3583            if options.trunk:
3584                if options.update:
3585                    pkg.update_trunk(dir=srcdir)
3586                else:
3587                    pkg.install_trunk(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3588            elif options.stable:
3589                if options.update:
3590                    pkg.update_stable(dir=srcdir)
3591                else:
3592                    pkg.install_stable(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3593            else:
3594                if options.update:
3595                    pkg.update_release(dir=srcdir)
3596                else:
3597                    pkg.install_release(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3598        #
3599        # Copy the <env>/Scripts/* files into <env>/bin
3600        #
3601        if os.path.exists(self.abshome_dir+os.sep+"Scripts"):
3602            for file in glob.glob(self.abshome_dir+os.sep+"Scripts"+os.sep+"*"):
3603                shutil.copy(file, self.abshome_dir+os.sep+"bin")
3604        #
3605        # Localize DOS cmd files
3606        #
3607        self.localize_cmd_files(self.abshome_dir, options.localize)
3608        #
3609        # Misc notifications
3610        #
3611        if not options.update:
3612            print ""
3613            print "-----------------------------------------------------------------"
3614            print "  Add %s to the PATH environment variable" % (self.home_dir+os.sep+"bin")
3615            print "-----------------------------------------------------------------"
3616        print ""
3617        print "Finished installation in '%s'" % self.home_dir
3618
3619    def localize_cmd_files(self, dir, force_localization=False):
3620        """
3621        Hard-code the path to Python that is used in the Python CMD files that
3622        are installed.
3623        """
3624        if not (sys.platform.startswith('win') or force_localization):
3625            return
3626        for file in self.cmd_files:
3627            INPUT = open(join(dir,'bin',file), 'r')
3628            content = "".join(INPUT.readlines())
3629            INPUT.close()
3630            content = content.replace('__VIRTUAL_ENV__',dir)
3631            OUTPUT = open(join(dir,'bin',file), 'w')
3632            OUTPUT.write(content)
3633            OUTPUT.close()
3634
3635    def svnjoin(*args):
3636        return '/'.join(args[1:])
3637
3638    def install_auxdirs(self, options):
3639        for todir,pkg,fromdir in self.auxdir:
3640            pkgroot = self.sw_dict[pkg].pkgroot
3641            if options.update:
3642                cmd = [Repository.svn,'update','-q',self.svnjoin(self.abshome_dir, todir)]
3643            else:
3644                if options.clear:
3645                    rmtree( join(self.abshome_dir,todir) )
3646                cmd = [Repository.svn,Repository.svn_get,'-q',self.svnjoin(pkgroot,fromdir),join(self.abshome_dir,todir)]
3647            print "Running command '%s'" % " ".join(cmd)
3648            call_subprocess(cmd, filter_stdout=filter_python_develop,show_stdout=True)
3649
3650    def read_config_file(self, file=None, fp=None):
3651        """
3652        Read a config file.
3653        """
3654        parser = OrderedConfigParser()
3655        if not fp is None:
3656            parser.readfp(fp, '<default configuration>')
3657        elif not os.path.exists(file):
3658            if not '/' in file and not self.config_file is None:
3659                file = os.path.dirname(self.config_file)+"/"+file
3660            try:
3661                if sys.version_info[:2] <= (2,5):
3662                    output = urllib2.urlopen(file).read()
3663                else:
3664                    output = urllib2.urlopen(file, timeout=30).read()
3665            except Exception, err:
3666                print "Problems opening configuration url:",file
3667                raise
3668            fp = StringIO.StringIO(output)
3669            parser.readfp(fp, file)
3670            fp.close()
3671        else:
3672            if not file in parser.read(file):
3673                raise IOError, "Error while parsing file %s." % file
3674        sections = parser.sections()
3675        if 'installer' in sections:
3676            for option, value in parser.items('installer'):
3677                setattr(self, option, apply_template(value, os.environ) )
3678        if 'localize' in sections:
3679            for option, value in parser.items('localize'):
3680                self.add_dos_cmd(option)
3681        for sec in sections:
3682            if sec in ['installer', 'localize']:
3683                continue
3684            if sec.endswith(':auxdir'):
3685                auxdir = sec[:-7]
3686                for option, value in parser.items(sec):
3687                    self.add_auxdir(auxdir, option, apply_template(value, os.environ) )
3688            else:
3689                options = {}
3690                for option, value in parser.items(sec):
3691                    options[option] = apply_template(value, os.environ)
3692                self.add_repository(sec, **options)
3693
3694    def write_config(self, filename=None, stream=None):
3695        if not filename is None:
3696            OUTPUT=open(filename,'w')
3697            self.write_config(stream=OUTPUT)
3698            OUTPUT.close()
3699        else: 
3700            for repos in self.sw_packages:
3701                repos.write_config(stream)
3702                print >>stream, ""
3703            if len(self.cmd_files) > 0:
3704                print >>stream, "[localize]"
3705                for file in self.cmd_files:
3706                    print >>stream, file+"="
3707                print >>stream, "\n"
3708       
3709
3710
3711def configure(installer):
3712    """
3713    A dummy configuration function.
3714    """
3715    return installer
3716
3717def create_installer():
3718    return Installer()
3719
3720def get_installer():
3721    """
3722    Return an instance of the installer object.  If this object
3723    does not already exist, then create the object and use the
3724    configure() function to customize it based on the end-user's
3725    needs.
3726
3727    The argument to this function is the class type that will be
3728    constructed if needed.
3729    """
3730    try:
3731        return get_installer.installer
3732    except:
3733        get_installer.installer = configure( create_installer() )
3734        return get_installer.installer
3735   
3736
3737#
3738# Override the default definition of rmtree, to better handle MSWindows errors
3739# that are associated with read-only files
3740#
3741def handleRemoveReadonly(func, path, exc):
3742  excvalue = exc[1]
3743  if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
3744      os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
3745      func(path)
3746  else:
3747      raise
3748
3749def rmtree(dir):
3750    if os.path.exists(dir):
3751        logger.notify('Deleting tree %s', dir)
3752        shutil.rmtree(dir, ignore_errors=False, onerror=handleRemoveReadonly)
3753    else:
3754        logger.info('Do not need to delete %s; already gone', dir)
3755
3756#
3757# This is a monkey patch, to add control for exception management.
3758#
3759vpy_main = main
3760vpy_main.raise_exceptions=False
3761def main():
3762    if sys.platform != 'win32':
3763        if os.environ.get('TMPDIR','') == '.':
3764            os.environ['TMPDIR'] = '/tmp'
3765        elif os.environ.get('TEMPDIR','') == '.':
3766            os.environ['TEMPDIR'] = '/tmp'
3767    try:
3768        vpy_main()
3769    except Exception, err:
3770        if vpy_main.raise_exceptions:
3771            raise
3772        print ""
3773        print "ERROR:",str(err)
3774
3775#
3776# This is a monkey patch, to control the execution of the install_setuptools()
3777# function that is defined by virtualenv.
3778#
3779default_install_setuptools = install_setuptools
3780
3781def install_setuptools(py_executable, unzip=False):
3782    try:
3783        if install_setuptools.use_default:
3784            default_install_setuptools(py_executable, unzip)
3785    except OSError, err:
3786        print "-----------------------------------------------------------------"
3787        print "Error installing the 'setuptools' package!"
3788        if os.environ['HTTP_PROXY'] == '':
3789            print ""
3790            print "WARNING: you may need to set your HTTP_PROXY environment variable!"
3791        print "-----------------------------------------------------------------"
3792        sys.exit(0)
3793
3794install_setuptools.use_default=True
3795
3796
3797#
3798# This is a monkey patch, to control the execution of the install_pip()
3799# function that is defined by virtualenv.
3800#
3801default_install_pip = install_pip
3802
3803def install_pip(*args, **kwds):
3804    try:
3805        if install_pip.use_default:
3806            default_install_pip(*args, **kwds)
3807    except OSError, err:
3808        print "-----------------------------------------------------------------"
3809        print "Error installing the 'pip' package!"
3810        if os.environ['HTTP_PROXY'] == '':
3811            print ""
3812            print "WARNING: you may need to set your HTTP_PROXY environment variable!"
3813        print "-----------------------------------------------------------------"
3814        sys.exit(0)
3815
3816install_pip.use_default=True
3817
3818
3819#
3820# The following methods will be called by virtualenv
3821#
3822def extend_parser(parser):
3823    installer = get_installer()
3824    installer.modify_parser(parser)
3825
3826def adjust_options(options, args):
3827    installer = get_installer()
3828    installer.get_homedir(options, args)
3829    installer.adjust_options(options, args)
3830    installer.setup_installer(options)
3831   
3832def after_install(options, home_dir):
3833    installer = get_installer()
3834    installer.install_packages(options)
3835
3836
3837
3838#
3839# Imported from coopr.py
3840#
3841
3842#  _________________________________________________________________________
3843#
3844#  Coopr: A COmmon Optimization Python Repository
3845#  Copyright (c) 2008 Sandia Corporation.
3846#  This software is distributed under the BSD License.
3847#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
3848#  the U.S. Government retains certain rights in this software.
3849#  _________________________________________________________________________
3850
3851import sys
3852
3853class CooprInstaller(Installer):
3854
3855    def __init__(self):
3856        Installer.__init__(self)
3857        self.default_dirname='coopr'
3858        self.config_file='https://software.sandia.gov/svn/public/coopr/vpy/installer.ini'
3859
3860    def modify_parser(self, parser):
3861        Installer.modify_parser(self, parser)
3862
3863        parser.add_option('--coin',
3864            help='Use one or more packages from the Coin Bazaar software repository.  Multiple packages are specified with a comma-separated list.',
3865            action='store',
3866            dest='coin',
3867            default=None)
3868
3869    def get_other_packages(self, options):
3870        if options.coin is None:
3871            return
3872        for pkg in options.coin.split(','):
3873            if pkg is '':
3874                continue
3875            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))
3876
3877    def install_packages(self, options):
3878        Installer.install_packages(self, options)
3879        if sys.version_info[:2] < (2,5):
3880            print ""
3881            print "-----------------------------------------------------------------"
3882            print " WARNING: Most Coopr packages will only work with Python 2.5 or"
3883            print "          newer.  You have installed Coopr with:"
3884            print sys.version
3885            print "-----------------------------------------------------------------"
3886
3887            print ""
3888
3889def create_installer():
3890    return CooprInstaller()
3891
3892
3893##file site.py
3894SITE_PY = """
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
4025yBXo8FFND74JkgILcmKn2vJbYxD8H2/QG9E=
4026""".decode("base64").decode("zlib")
4027
4028##file ez_setup.py
4029EZ_SETUP_PY = """
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
4096178BYnMUkw==
4097""".decode("base64").decode("zlib")
4098
4099##file distribute_setup.py
4100DISTRIBUTE_SETUP_PY = """
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
4178""".decode("base64").decode("zlib")
4179
4180##file activate.sh
4181ACTIVATE_SH = """
4182eJytVFFv2jAQfs+vuIU+QDWK+tqKB6oigdRC1bBOW1sZk1yIpWAj2yGj0/77ziFAUijStPIA2Hc+
4183f/7u+64Bk0QYiEWKsMiMhRlCZjCCXNgEfKMyHSLMhOzw0IoVt+jDeazVAmbcJOdeA9Yqg5BLqSzo
4184TIKwEAmNoU3Xnhfh9hQ0W/DbA/o0QKNBCyqNAOVKaCUXKC2suBZ8lqIpskQMz9CW4J+x8d0texo+
4185Tr717thDbzLw4RWuwSYoi0z3cdvdY6m7DPy1VNoWibu9TDocB4eKeCxOwvgxGYxHg/F9/xiYXfAA
41860v7YAbBd6CS8ehaBLCktmmgSlRGpEVqiv+gPcBnBm0m+Qp6IMIGErxA4/VAoVIuFC9uE26L1ZSkS
4187QMjTlCRgFcwJAXWU/sVKu8WSk0bKo+YC4DvJRGW2DFsh52WZWqIjCM4cuRAmXM7RQE5645H7WoPT
4188Dl1LulgScozeUX/TC6jpbbVZ/QwG7Kn/GAzHoyPkF09r6xo9HzUxuDzWveDyoG2UeNCv4PJko8rw
4189FsImZRvtj572wL4QLgLSBV8qGaGxOnOewXfYGhBgGsM24cu729sutDXb9uo/HvlzExdaY0rdrxmt
4190Ys/63Z5Xgdr1GassGfO9koTqe7wDHxGNGw+Wi0p2h7Gb4YiNevd9xq7KtKpFd7j3inds0Q5FrBN7
4191LtIUYi5St1/NMi7LKdZpDhdLuwZ6FwkTmhsTUMaMR2SNdc7XLaoXFrahqQdTqtUs6Myu4YoUu6vb
4192guspCFm4ytsL6sNB8IFtu7UjFWlUnO00s7nhDWqssdth0Lu567OHx/H9w+TkjYWKd8ItyvlTAo+S
4193LxBeanVf/GmhP+rsoR8a4EwpeEpTgRgin0OPdiQZdy7CctYrLcq5XR5BhMTa5VWnk+f5xRtasvrq
4194gsZBx6jY5lxjh7sqnbrvnisQp1T6KNiX6fQV9m/D1GC9SvPEQ1v7g+WIrxjaMf9Js/QT5uh/ztB/
4195n5/b2Uk0/AXm/2MV
4196""".decode("base64").decode("zlib")
4197
4198##file activate.bat
4199ACTIVATE_BAT = """
4200eJyFUssKgzAQvAfyD3swYH+hItSiVKlGsalQKOyhauvFHOr/U+MzFcWc9jEzO7vkVLw+EmRZUvIt
4201GsiCVNydED2e2YhahkgJJVUJtWwgL8qqLnJI0jhKBJiUQPsUv6/YRmJcKDkMlBGOcehOmptctgJj
4202e2IP4cfcjyNvFOwVp/JSdWqMygq+MthmkwHNojmfhjuRh3iAGffncsPYhpl2mm5sbY+9QzjC7ylt
4203sFy6LTEL3rKRcLsGicrXV++4HVz1jzN4Vta+BnsingM+nMLSiB53KfkBsnmnEA==
4204""".decode("base64").decode("zlib")
4205
4206##file deactivate.bat
4207DEACTIVATE_BAT = """
4208eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
4209FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL
4210i2dASrm4rFz9XLgAwJNbyQ==
4211""".decode("base64").decode("zlib")
4212
4213##file distutils-init.py
4214DISTUTILS_INIT = """
4215eJytVl2L6zYQffevGBKK7XavKe3bhVBo78uFSyml0IdlEVpbTtR1JCMpm6S/vjOSY0v+uO1DDbs4
42160tF8nJk5sjz32jjQNpPhzd7H1ys3SqqjhcfCL1q18vgbN1YY2Kc/pQWlHXB4l8ZdeCfUO5x1c+nE
4217E1gNVwE1V3CxAqQDp6GVqgF3EmBd08nXLGukUfws4IDBVD13p2pYoS3rLk52ltF6hPhLS1XM4EUc
4218VsVYKzvBWPkE+WgmLzPZjkaUNmd6KVI3JRwWoRSLM6P98mMG+Dw4q+il8Ev07P7ATCNmRlfQ8/qN
4219HwVwB99Y4H0vMHAi6BWZUoEhoqXTNXdSK+A2LN6tE+fJ0E+7MhOdFSEM5lNgrJIKWXDF908wy87D
4220xE3UoHsxkegZTaHIHGNSSYfm+ntelpURvCnK7NEWBI/ap/b8Z1m232N2rj7B60V2DRM3B5NpaLSw
4221KnfwpvQVTviHOR+F88lhQyBAGlE7be6DoRNg9ldsG3218IHa6MRNU+tGBEYIggwafRk6yzsXDcVU
42229Ua08kYxt+F3x12LRaQi52j0xx/ywFxrdMRqVevzmaummlIYEp0WsCAaX8cFb6buuLUTqEgQQ6/Q
422304iWRoF38m/BdE8VtlBY0bURiB6KG1crpMZwc2fIjqWh+1UrkSLpWUIP8PySwLKv4qPGSVqDuMPy
4224dywQ+gS7L1irXVkm5pJsq3l+Ib1lMOvUrxI+/mBBY4KB+WpUtcO06RtzckNvQ6vYj1lGoZM2sdDG
4225fryJPYJVn/Cfka8XSqNaoLKhmOlqXMzW9+YBVp1EtIThZtOwzCRvMaARa+0xD0b2kcaJGwJsMbc7
4226hLUfY4vKvsCOBdvDnyfuRbzmXRdGTZgPF7oGQkJACWVD22IMQdhx0npt5S2f+pXO+OwH6d+hwiS5
42277IJOjcK2emj1zBy1aONHByfAMoraw6WlrSIFTbGghqASoRCjVncYROFpXM4uYSqhGnuVeGvks4jz
4228cjnCoR5GnPW7KOh4maVbdFeoplgJ3wh3MSrAsv/QuMjOspnTKRl1fTYqqNisv7uTVnhF1GhoBFbp
4229lh+OcXN2riA5ZrYXtWxlfcDuC8U5kLoN3CCJYXGpesO6dx6rU0zGMtjU6cNlmW0Fid8Sja4ZG+Z3
4230fTPbyj+mZnZ2wSQK8RaT9Km0ySRuLpm0DkUUL0ra3WQ2BgGJ7v9I9SKqNKZ/IR4R28RHm+vEz5ic
4231nZ2IH7bfub8pU1PR3gr10W7xLTfHh6Z6bgZ7K14G7Mj/1z5J6MFo6V5e07H0Ou78dTyeI+mxKOpI
4232eC2KMSj6HKxd6Uudf/n886fPv+f++x1lbASlmjQuPz8OvGA0j7j2eCu/4bcW6SFeCuNJ0W1GQHI5
4233iwC9Ey0bjtHd9P4dPA++XxLnZDVuxvFEtlm3lf5a2c02u2LRYXHH/AOs8pIa
4234""".decode("base64").decode("zlib")
4235
4236##file distutils.cfg
4237DISTUTILS_CFG = """
4238eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
4239xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
42409FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
4241""".decode("base64").decode("zlib")
4242
4243##file activate_this.py
4244ACTIVATE_THIS = """
4245eJyNUk2L3DAMvftXiCxLEphmSvc2MIcu9NaWHnopwxCcRNlRN7GD7clM/n0lp5mPZQs1JLb8pKcn
4246WUmSPE9w9GReAM9Yt9RhFg7kSzmtoKE6ZGU0ynJ7AfIcJnuEE3Wd0nWgUQcEQWEkF466QzMCf+Ss
42476dGEQqmfgtbaQIWcDxs4HdBElv7og1wBg3gmH0TMjykcrAEyAd3gkP8rMDaocMDbHBWZ9RBdVZIk
4248SgU3bRTwWjQrPNc4BPiue/zinHUz7DRxws/eowtkTUSyiMhKfi2y3NHMdXX0itcOpYMOh3Ww61g8
4249luJSDFP6tmH3ftyki2eeJ7mifrAugJ/8crReqUqztC0fC4kuGnKGxWf/snXlZb8kzXMmboW0GDod
4250Wut62G4hPZF5+pTO5XtiKYOuX/UL+ptcvy2ZTPKvIP1KFdeTiuuHxTXNFXYe/5+km0nmJ3r0KTxG
4251YSM6z23fbZ7276Tg9x5LdiuFjok7noks1sP2tWscpeRX6KaRnRuT3WnKlQQ51F3JlC2dmSvSRENd
4252j3wvetUDfLOjDDLPYtPwjDJb7yHYeNXyMPMLtdEQKRtl8HQrdLdX3O4YxZP7RvfcNH6ZCPMsi8td
4253qZvLAN7yFnoY0DSZhOUXj4WWy+tZ8190ud1tPu5Zzy2N+gOGaVfA
4254""".decode("base64").decode("zlib")
4255
4256if __name__ == '__main__':
4257    main()
4258
4259# pyutilib.virtualenv: ignoring comment
4260## Copy python.exe.manifest
4261## Monkeypatch distutils.sysconfig
Note: See TracBrowser for help on using the repository browser.