source: coopr.misc/stable/2.2/util/coopr_install @ 2436

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

Merged revisions 2389-2435 via svnmerge from
https://software.sandia.gov/svn/public/coopr/coopr.misc/trunk

........

r2395 | wehart | 2010-02-23 13:29:35 -0700 (Tue, 23 Feb 2010) | 2 lines


Update due to changes with pyutilib.virtualenv.

........

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