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

Last change on this file since 2384 was 2384, checked in by wehart, 10 years ago

Updated coopr_install due to changes
in pyutilib.virtual that check to ensure that
urlopen() is called with the correct arguments.

Added a warning when installing with Python 2.4

  • Property svn:executable set to *
File size: 161.8 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.easy_install_path, '-q', self.pypi])
3100            elif preinstall: 
3101                if not os.path.exists(dir):
3102                    self.run([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.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   Repository.python += '.exe'
3124   Repository.svn += '.exe'
3125
3126
3127def filter_python_develop(line):
3128    if not line.strip():
3129        return Logger.DEBUG
3130    for prefix in ['Searching for', 'Reading ', 'Best match: ', 'Processing ',
3131                   'Moving ', 'Adding ', 'running ', 'writing ', 'Creating ',
3132                   'creating ', 'Copying ']:
3133        if line.startswith(prefix):
3134            return Logger.DEBUG
3135    return Logger.NOTIFY
3136
3137
3138def apply_template(str, d):
3139    t = string.Template(str)
3140    return t.safe_substitute(d)
3141
3142
3143wrapper = textwrap.TextWrapper(subsequent_indent="    ")
3144
3145
3146class Installer(object):
3147
3148    def __init__(self):
3149        self.description="This script manages the installation of packages into a virtual Python installation."
3150        self.home_dir = None
3151        self.default_dirname='python'
3152        self.abshome_dir = None
3153        self.sw_packages = []
3154        self.sw_dict = {}
3155        self.cmd_files = []
3156        self.auxdir = []
3157        self.config=None
3158        self.config_file=None
3159        self.README="""
3160#
3161# Virtual Python installation generated by the %s script.
3162#
3163# This directory is managed with virtualenv, which creates a
3164# virtual Python installation.  If the 'bin' directory is put in
3165# user's PATH environment, then the bin/python command can be used
3166# without further installation.
3167#
3168# Directories:
3169#   admin      Administrative data for maintaining this distribution
3170#   bin        Scripts and executables
3171#   dist       Python packages that are not intended for development
3172#   include    Python header files
3173#   lib        Python libraries and installed packages
3174#   src        Python packages whose source files can be
3175#              modified and used directly within this virtual Python
3176#              installation.
3177#   Scripts    Python bin directory (used on MS Windows)
3178#
3179""" % sys.argv[0]
3180
3181    def add_repository(self, *args, **kwds):
3182        if not 'root' in kwds and not 'pypi' in kwds and not 'release' in kwds and not 'trunk' in kwds and not 'stable' in kwds:
3183            raise IOError, "No repository info specified for repository "+args[0]
3184        repos = Repository( *args, **kwds)
3185        self.sw_dict[repos.name] = repos
3186        self.sw_packages.append( repos )
3187
3188    def add_dos_cmd(self, file):
3189        self.cmd_files.append( file )
3190
3191    def add_auxdir(self, package, todir, fromdir):
3192        self.auxdir.append( (todir, package, fromdir) )
3193
3194    def modify_parser(self, parser):
3195        self.default_windir = 'C:\\'+self.default_dirname
3196        self.default_unixdir = './'+self.default_dirname
3197        #
3198        parser.add_option('--debug',
3199            help='Configure script to generate debugging IO and to raise exceptions.',
3200            action='store_true',
3201            dest='debug',
3202            default=False)
3203
3204        parser.add_option('--trunk',
3205            help='Install trunk branches of Python software.',
3206            action='store_true',
3207            dest='trunk',
3208            default=False)
3209
3210        parser.add_option('--stable',
3211            help='Install stable branches of Python software.',
3212            action='store_true',
3213            dest='stable',
3214            default=False)
3215
3216        parser.add_option('--update',
3217            help='Update all Python packages.',
3218            action='store_true',
3219            dest='update',
3220            default=False)
3221
3222        parser.add_option('--proxy',
3223            help='Set the HTTP_PROXY environment with this option.',
3224            action='store',
3225            dest='proxy',
3226            default=None)
3227
3228        parser.add_option('--preinstall',
3229            help='Prepare an installation that will be used to build a MS Windows installer.',
3230            action='store_true',
3231            dest='preinstall',
3232            default=False)
3233
3234        parser.add_option('--offline',
3235            help='Perform installation offline, using source extracted from ZIP files.',
3236            action='store_true',
3237            dest='offline',
3238            default=False)
3239
3240        parser.add_option('--zip',
3241            help='Add ZIP files that are use define this installation.',
3242            action='append',
3243            dest='zip',
3244            default=[])
3245
3246        parser.add_option('--use-pythonpath',
3247            help="By default, the PYTHONPATH is ignored when installing.  This option allows the 'easy_install' tool to search this path for related Python packages, which are then installed.",
3248            action='store_true',
3249            dest='use_pythonpath',
3250            default=False)
3251
3252        parser.add_option(
3253            '--site-packages',
3254            dest='no_site_packages',
3255            action='store_false',
3256            help="Setup the virtual environment to use the global site-packages",
3257            default=True)
3258
3259        parser.add_option('--config',
3260            help='Use an INI config file to specify the packages used in this installation.  Using this option clears the initial configuration, but multiple uses of this option will add package specifications.',
3261            action='append',
3262            dest='config_files',
3263            default=[])
3264
3265        parser.add_option('--keep-config',
3266            help='Keep the initial configuration data that was specified if the --config option is specified.',
3267            action='store_true',
3268            dest='keep_config',
3269            default=False)
3270
3271        parser.add_option('--localize',
3272            help='Force localization of DOS scripts on Linux platforms',
3273            action='store_true',
3274            dest='localize',
3275            default=False)
3276
3277        #
3278        # Change the virtualenv options
3279        #
3280        parser.get_option("--python").help = "Specify the Python interpreter to use, e.g., --python=python2.5 will install with the python2.5 interpreter."
3281        parser.remove_option("--relocatable")
3282        parser.remove_option("--version")
3283        parser.remove_option("--unzip-setuptools")
3284        parser.remove_option("--no-site-packages")
3285        parser.remove_option("--clear")
3286        #
3287        # Add description
3288        #
3289        parser.description=self.description
3290        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>'."
3291       
3292
3293    def adjust_options(self, options, args):
3294        #
3295        # Force options.clear to be False.  This allows us to preserve the logic
3296        # associated with --clear, which we may want to use later.
3297        #
3298        options.clear=False
3299        #
3300        global vpy_main
3301        if options.debug:
3302            vpy_main.raise_exceptions=True
3303        #
3304        global logger
3305        verbosity = options.verbose - options.quiet
3306        self.logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
3307        logger = self.logger
3308        #
3309        if options.update and (options.stable or options.trunk):
3310            self.logger.fatal("ERROR: cannot specify --stable or --trunk when specifying the --update option.")
3311            sys.exit(1000)
3312        if options.update and len(options.config_files) > 0:
3313            self.logger.fatal("ERROR: cannot specify --config when specifying the --update option.")
3314            sys.exit(1000)
3315        if options.update and options.keep_config:
3316            self.logger.fatal("ERROR: cannot specify --keep-config when specifying the --update option.")
3317            sys.exit(1000)
3318        if len(args) > 1:
3319            self.logger.fatal("ERROR: installer script can only have one argument")
3320            sys.exit(1000)
3321        #
3322        # Error checking
3323        #
3324        if not options.preinstall and (os.path.exists(self.abshome_dir) ^ options.update):
3325            if options.update:
3326                self.logger.fatal(wrapper.fill("ERROR: The 'update' option is specified, but the installation path '%s' does not exist!" % self.home_dir))
3327                sys.exit(1000)
3328            elif os.path.exists(join(self.abshome_dir,'bin')):
3329                    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))
3330                    sys.exit(1000)
3331        if len(args) == 0:
3332            args.append(self.abshome_dir)
3333        #
3334        # Parse config files
3335        #
3336        if options.update:
3337            self.config=None
3338            options.config_files.append( join(self.abshome_dir, 'admin', 'config.ini') )
3339        if not self.config is None and (len(options.config_files) == 0 or options.keep_config):
3340            fp = StringIO.StringIO(self.config)
3341            self.read_config_file(fp=fp)
3342            fp.close()
3343        if not self.config_file is None and (len(options.config_files) == 0 or options.keep_config):
3344            self.read_config_file(file=self.config_file)
3345        for file in options.config_files:
3346            self.read_config_file(file=file)
3347        print "-----------------------------------------------------------------"
3348        print "Finished processing configuration information."
3349        print "-----------------------------------------------------------------"
3350        print " START - Configuration summary"
3351        print "-----------------------------------------------------------------"
3352        self.write_config(stream=sys.stdout)
3353        print "-----------------------------------------------------------------"
3354        print " END - Configuration summary"
3355        print "-----------------------------------------------------------------"
3356        #
3357        # If applying preinstall, then only do subversion exports
3358        #
3359        if options.preinstall:
3360            Repository.svn_get='export'
3361
3362    def get_homedir(self, options, args):
3363        #
3364        # Figure out the installation directory
3365        #
3366        if len(args) == 0:
3367            path = self.guess_path()
3368            if path is None or options.preinstall:
3369                # Install in a default location.
3370                if sys.platform == 'win32':
3371                    home_dir = self.default_windir
3372                else:
3373                    home_dir = self.default_unixdir
3374            else:
3375                home_dir = os.path.dirname(os.path.dirname(path))
3376        else:
3377            home_dir = args[0]
3378        self.home_dir = home_dir
3379        self.abshome_dir = os.path.abspath(home_dir)
3380
3381    def guess_path(self):
3382        return None
3383
3384    def setup_installer(self, options):
3385        if options.preinstall:
3386            print "Creating preinstall zip file in '%s'" % self.home_dir
3387        elif options.update:
3388            print "Updating existing installation in '%s'" % self.home_dir
3389        else:
3390            print "Starting fresh installation in '%s'" % self.home_dir
3391        #
3392        # Setup HTTP proxy
3393        #
3394        if options.offline:
3395            os.environ['HTTP_PROXY'] = ''
3396            os.environ['http_proxy'] = ''
3397        else:
3398            proxy = ''
3399            if not options.proxy is None:
3400                proxy = options.proxy
3401            if proxy is '':
3402                proxy = os.environ.get('HTTP_PROXY', '')
3403            if proxy is '':
3404                proxy = os.environ.get('http_proxy', '')
3405            os.environ['HTTP_PROXY'] = proxy
3406            os.environ['http_proxy'] = proxy
3407            print "  using the HTTP_PROXY environment: %s" % proxy
3408            print ""
3409        #
3410        # Disable the PYTHONPATH, to isolate this installation from
3411        # other Python installations that a user may be working with.
3412        #
3413        if not options.use_pythonpath:
3414            try:
3415                del os.environ["PYTHONPATH"]
3416            except:
3417                pass
3418        #
3419        # If --preinstall is declared, then we remove the directory, and prepare a ZIP file
3420        # that contains the full installation.
3421        #
3422        if options.preinstall:
3423            print "-----------------------------------------------------------------"
3424            print " STARTING preinstall in directory %s" % self.home_dir
3425            print "-----------------------------------------------------------------"
3426            rmtree(self.abshome_dir)
3427            os.mkdir(self.abshome_dir)
3428        #
3429        # When preinstalling or working offline, disable the
3430        # default install_setuptools() function.
3431        #
3432        if options.preinstall or options.offline:
3433            install_setuptools.use_default=False
3434            install_pip.use_default=False
3435        #
3436        # If we're clearing the current installation, then remove a bunch of
3437        # directories
3438        #
3439        elif options.clear:
3440            path = join(self.abshome_dir,'src')
3441            if os.path.exists(path):
3442                rmtree(path)
3443        #
3444        # Open up zip files
3445        #
3446        for file in options.zip:
3447            unzip_file(file, dir=self.abshome_dir)
3448
3449        if options.preinstall or not options.offline:
3450            self.get_packages(options)
3451        else:
3452            self.sw_packages.insert( 0, Repository('virtualenv', pypi='virtualenv') )
3453            self.sw_packages.insert( 0, Repository('pip', pypi='pip') )
3454            self.sw_packages.insert( 0, Repository('setuptools', pypi='setuptools') )
3455            #
3456            # Configure the package versions, for offline installs
3457            #
3458            for pkg in self.sw_packages:
3459                pkg.guess_versions(True)
3460
3461    def get_packages(self, options):
3462        #
3463        # Setup the 'admin' directory
3464        #
3465        if not os.path.exists(self.abshome_dir):
3466            os.mkdir(self.abshome_dir)
3467        if not os.path.exists(join(self.abshome_dir,'admin')):
3468            os.mkdir(join(self.abshome_dir,'admin'))
3469        if options.update:
3470            INPUT=open(join(self.abshome_dir,'admin',"virtualenv.cfg"),'r')
3471            options.trunk = INPUT.readline().strip() != 'False'
3472            options.stable = INPUT.readline().strip() != 'False'
3473            INPUT.close()
3474        else:
3475            OUTPUT=open(join(self.abshome_dir,'admin',"virtualenv.cfg"),'w')
3476            print >>OUTPUT, options.trunk
3477            print >>OUTPUT, options.stable
3478            OUTPUT.close()
3479            self.write_config( join(self.abshome_dir,'admin','config.ini') )
3480        #
3481        # Setup package directories
3482        #
3483        if not os.path.exists(join(self.abshome_dir,'dist')):
3484            os.mkdir(join(self.abshome_dir,'dist'))
3485        if not os.path.exists(self.abshome_dir+os.sep+"src"):
3486            os.mkdir(self.abshome_dir+os.sep+"src")
3487        if not os.path.exists(self.abshome_dir+os.sep+"bin"):
3488            os.mkdir(self.abshome_dir+os.sep+"bin")
3489        #
3490        # Get source packages
3491        #
3492        self.sw_packages.insert( 0, Repository('virtualenv', pypi='virtualenv') )
3493        self.sw_packages.insert( 0, Repository('pip', pypi='pip') )
3494        if options.preinstall:
3495            #
3496            # When preinstalling, add the setuptools package to the installation list
3497            #
3498            self.sw_packages.insert( 0, Repository('setuptools', pypi='setuptools') )
3499        #
3500        # Add Coopr Forum packages
3501        #
3502        self.get_other_packages(options)
3503        #
3504        # Get package source
3505        #
3506        for pkg in self.sw_packages:
3507            pkg.guess_versions(False)
3508            if not pkg.install:
3509                pkg.find_pkgroot(trunk=options.trunk, stable=options.stable, release=not (options.trunk or options.stable))
3510                continue
3511            if pkg.dev:
3512                tmp = join(self.abshome_dir,'src',pkg.name)
3513            else:
3514                tmp = join(self.abshome_dir,'dist',pkg.name)
3515            if options.trunk:
3516                if not options.update:
3517                    pkg.install_trunk(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3518            elif options.stable:
3519                if not options.update:
3520                    pkg.install_stable(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3521            else:
3522                if not options.update:
3523                    pkg.install_release(dir=tmp, install=False, preinstall=options.preinstall, offline=options.offline)
3524        if options.update or not os.path.exists(join(self.abshome_dir,'doc')):
3525            self.install_auxdirs(options)
3526        #
3527        # Create a README.txt file
3528        #
3529        OUTPUT=open(join(self.abshome_dir,"README.txt"),"w")
3530        print >>OUTPUT, self.README.strip()
3531        OUTPUT.close()
3532        #
3533        # Finalize preinstall
3534        #
3535        if options.preinstall:
3536            print "-----------------------------------------------------------------"
3537            print " FINISHED preinstall in directory %s" % self.home_dir
3538            print "-----------------------------------------------------------------"
3539            os.chdir(self.abshome_dir)
3540            zip_file(self.default_dirname+'.zip', ['.'])
3541            sys.exit(0)
3542
3543    def get_other_packages(self, options):
3544        #
3545        # Used by subclasses of Installer to
3546        # add packages that were requested through other means....
3547        #
3548        pass
3549       
3550    def install_packages(self, options):
3551        #
3552        # Set the bin directory
3553        #
3554        if os.path.exists(self.abshome_dir+os.sep+"Scripts"):
3555            bindir = join(self.abshome_dir,"Scripts")
3556        else:
3557            bindir = join(self.abshome_dir,"bin")
3558        Repository.easy_install_path = os.path.abspath(join(bindir, 'easy_install'))
3559        Repository.python = os.path.abspath(join(bindir, 'python'))
3560        #
3561        # Install the related packages
3562        #
3563        for pkg in self.sw_packages:
3564            if not pkg.install:
3565                pkg.find_pkgroot(trunk=options.trunk, stable=options.stable, release=not (options.trunk or options.stable))
3566                continue
3567            if pkg.dev:
3568                srcdir = join(self.abshome_dir,'src',pkg.name)
3569            else:
3570                srcdir = join(self.abshome_dir,'dist',pkg.name)
3571            if options.trunk:
3572                if options.update:
3573                    pkg.update_trunk(dir=srcdir)
3574                else:
3575                    pkg.install_trunk(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3576            elif options.stable:
3577                if options.update:
3578                    pkg.update_stable(dir=srcdir)
3579                else:
3580                    pkg.install_stable(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3581            else:
3582                if options.update:
3583                    pkg.update_release(dir=srcdir)
3584                else:
3585                    pkg.install_release(dir=srcdir, preinstall=options.preinstall, offline=options.offline)
3586        #
3587        # Copy the <env>/Scripts/* files into <env>/bin
3588        #
3589        if os.path.exists(self.abshome_dir+os.sep+"Scripts"):
3590            for file in glob.glob(self.abshome_dir+os.sep+"Scripts"+os.sep+"*"):
3591                shutil.copy(file, self.abshome_dir+os.sep+"bin")
3592        #
3593        # Localize DOS cmd files
3594        #
3595        self.localize_cmd_files(self.abshome_dir, options.localize)
3596        #
3597        # Misc notifications
3598        #
3599        if not options.update:
3600            print ""
3601            print "-----------------------------------------------------------------"
3602            print "  Add %s to the PATH environment variable" % (self.home_dir+os.sep+"bin")
3603            print "-----------------------------------------------------------------"
3604        print ""
3605        print "Finished installation in '%s'" % self.home_dir
3606
3607    def localize_cmd_files(self, dir, force_localization=False):
3608        """
3609        Hard-code the path to Python that is used in the Python CMD files that
3610        are installed.
3611        """
3612        if not (sys.platform.startswith('win') or force_localization):
3613            return
3614        for file in self.cmd_files:
3615            INPUT = open(join(dir,'bin',file), 'r')
3616            content = "".join(INPUT.readlines())
3617            INPUT.close()
3618            content = content.replace('__VIRTUAL_ENV__',dir)
3619            OUTPUT = open(join(dir,'bin',file), 'w')
3620            OUTPUT.write(content)
3621            OUTPUT.close()
3622
3623    def svnjoin(*args):
3624        return '/'.join(args[1:])
3625
3626    def install_auxdirs(self, options):
3627        for todir,pkg,fromdir in self.auxdir:
3628            pkgroot = self.sw_dict[pkg].pkgroot
3629            if options.update:
3630                cmd = [Repository.svn,'update','-q',self.svnjoin(self.abshome_dir, todir)]
3631            else:
3632                if options.clear:
3633                    rmtree( join(self.abshome_dir,todir) )
3634                cmd = [Repository.svn,Repository.svn_get,'-q',self.svnjoin(pkgroot,fromdir),join(self.abshome_dir,todir)]
3635            print "Running command '%s'" % " ".join(cmd)
3636            call_subprocess(cmd, filter_stdout=filter_python_develop,show_stdout=True)
3637
3638    def read_config_file(self, file=None, fp=None):
3639        """
3640        Read a config file.
3641        """
3642        parser = OrderedConfigParser()
3643        if not fp is None:
3644            parser.readfp(fp, '<default configuration>')
3645        elif not os.path.exists(file):
3646            if not '/' in file and not self.config_file is None:
3647                file = os.path.dirname(self.config_file)+"/"+file
3648            try:
3649                if sys.version_info[:2] <= (2,5):
3650                    output = urllib2.urlopen(file).read()
3651                else:
3652                    output = urllib2.urlopen(file, timeout=30).read()
3653            except Exception, err:
3654                print "Problems opening configuration url:",file
3655                raise
3656            fp = StringIO.StringIO(output)
3657            parser.readfp(fp, file)
3658            fp.close()
3659        else:
3660            if not file in parser.read(file):
3661                raise IOError, "Error while parsing file %s." % file
3662        sections = parser.sections()
3663        if 'installer' in sections:
3664            for option, value in parser.items('installer'):
3665                setattr(self, option, apply_template(value, os.environ) )
3666        if 'localize' in sections:
3667            for option, value in parser.items('localize'):
3668                self.add_dos_cmd(option)
3669        for sec in sections:
3670            if sec in ['installer', 'localize']:
3671                continue
3672            if sec.endswith(':auxdir'):
3673                auxdir = sec[:-7]
3674                for option, value in parser.items(sec):
3675                    self.add_auxdir(auxdir, option, apply_template(value, os.environ) )
3676            else:
3677                options = {}
3678                for option, value in parser.items(sec):
3679                    options[option] = apply_template(value, os.environ)
3680                self.add_repository(sec, **options)
3681
3682    def write_config(self, filename=None, stream=None):
3683        if not filename is None:
3684            OUTPUT=open(filename,'w')
3685            self.write_config(stream=OUTPUT)
3686            OUTPUT.close()
3687        else: 
3688            for repos in self.sw_packages:
3689                repos.write_config(stream)
3690                print >>stream, ""
3691            if len(self.cmd_files) > 0:
3692                print >>stream, "[localize]"
3693                for file in self.cmd_files:
3694                    print >>stream, file+"="
3695                print >>stream, "\n"
3696       
3697
3698
3699def configure(installer):
3700    """
3701    A dummy configuration function.
3702    """
3703    return installer
3704
3705def create_installer():
3706    return Installer()
3707
3708def get_installer():
3709    """
3710    Return an instance of the installer object.  If this object
3711    does not already exist, then create the object and use the
3712    configure() function to customize it based on the end-user's
3713    needs.
3714
3715    The argument to this function is the class type that will be
3716    constructed if needed.
3717    """
3718    try:
3719        return get_installer.installer
3720    except:
3721        get_installer.installer = configure( create_installer() )
3722        return get_installer.installer
3723   
3724
3725#
3726# Override the default definition of rmtree, to better handle MSWindows errors
3727# that are associated with read-only files
3728#
3729def handleRemoveReadonly(func, path, exc):
3730  excvalue = exc[1]
3731  if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
3732      os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
3733      func(path)
3734  else:
3735      raise
3736
3737def rmtree(dir):
3738    if os.path.exists(dir):
3739        logger.notify('Deleting tree %s', dir)
3740        shutil.rmtree(dir, ignore_errors=False, onerror=handleRemoveReadonly)
3741    else:
3742        logger.info('Do not need to delete %s; already gone', dir)
3743
3744#
3745# This is a monkey patch, to add control for exception management.
3746#
3747vpy_main = main
3748vpy_main.raise_exceptions=False
3749def main():
3750    if sys.platform != 'win32':
3751        if os.environ.get('TMPDIR','') == '.':
3752            os.environ['TMPDIR'] = '/tmp'
3753        elif os.environ.get('TEMPDIR','') == '.':
3754            os.environ['TEMPDIR'] = '/tmp'
3755    try:
3756        vpy_main()
3757    except Exception, err:
3758        if vpy_main.raise_exceptions:
3759            raise
3760        print ""
3761        print "ERROR:",str(err)
3762
3763#
3764# This is a monkey patch, to control the execution of the install_setuptools()
3765# function that is defined by virtualenv.
3766#
3767default_install_setuptools = install_setuptools
3768
3769def install_setuptools(py_executable, unzip=False):
3770    try:
3771        if install_setuptools.use_default:
3772            default_install_setuptools(py_executable, unzip)
3773    except OSError, err:
3774        print "-----------------------------------------------------------------"
3775        print "Error installing the 'setuptools' package!"
3776        if os.environ['HTTP_PROXY'] == '':
3777            print ""
3778            print "WARNING: you may need to set your HTTP_PROXY environment variable!"
3779        print "-----------------------------------------------------------------"
3780        sys.exit(0)
3781
3782install_setuptools.use_default=True
3783
3784
3785#
3786# This is a monkey patch, to control the execution of the install_pip()
3787# function that is defined by virtualenv.
3788#
3789default_install_pip = install_pip
3790
3791def install_pip(*args, **kwds):
3792    try:
3793        if install_pip.use_default:
3794            default_install_pip(*args, **kwds)
3795    except OSError, err:
3796        print "-----------------------------------------------------------------"
3797        print "Error installing the 'pip' package!"
3798        if os.environ['HTTP_PROXY'] == '':
3799            print ""
3800            print "WARNING: you may need to set your HTTP_PROXY environment variable!"
3801        print "-----------------------------------------------------------------"
3802        sys.exit(0)
3803
3804install_pip.use_default=True
3805
3806
3807#
3808# The following methods will be called by virtualenv
3809#
3810def extend_parser(parser):
3811    installer = get_installer()
3812    installer.modify_parser(parser)
3813
3814def adjust_options(options, args):
3815    installer = get_installer()
3816    installer.get_homedir(options, args)
3817    installer.adjust_options(options, args)
3818    installer.setup_installer(options)
3819   
3820def after_install(options, home_dir):
3821    installer = get_installer()
3822    installer.install_packages(options)
3823
3824
3825
3826#
3827# Imported from coopr.py
3828#
3829
3830#  _________________________________________________________________________
3831#
3832#  Coopr: A COmmon Optimization Python Repository
3833#  Copyright (c) 2008 Sandia Corporation.
3834#  This software is distributed under the BSD License.
3835#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
3836#  the U.S. Government retains certain rights in this software.
3837#  _________________________________________________________________________
3838
3839import sys
3840
3841class CooprInstaller(Installer):
3842
3843    def __init__(self):
3844        Installer.__init__(self)
3845        self.default_dirname='coopr'
3846        self.config_file='https://software.sandia.gov/svn/public/coopr/vpy/installer.ini'
3847
3848    def modify_parser(self, parser):
3849        Installer.modify_parser(self, parser)
3850
3851        parser.add_option('--coin',
3852            help='Use one or more packages from the Coin Bazaar software repository.  Multiple packages are specified with a comma-separated list.',
3853            action='store',
3854            dest='coin',
3855            default='')
3856
3857    def get_other_packages(self, options):
3858        for pkg in options.coin.split(','):
3859            if pkg is '':
3860                continue
3861            if sys.version_info < (2,6,4):
3862                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))
3863            else:
3864                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))
3865
3866    def install_packages(self, options):
3867        Installer.install_packages(self, options)
3868        if sys.version_info[:2] < (2,5):
3869            print ""
3870            print "-----------------------------------------------------------------"
3871            print " WARNING: Most Coopr packages will only work with Python 2.5 or"
3872            print "          newer.  You have installed Coopr with:"
3873            print sys.version
3874            print "-----------------------------------------------------------------"
3875
3876            print ""
3877
3878def create_installer():
3879    return CooprInstaller()
3880
3881
3882##file site.py
3883SITE_PY = """
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
3989FXu98AQh0jVflJYd8rAfNaWB5brCDwWQAQD4w45f9EXnFMgpTeO60X2p/x7Qr7+6C6yrZAaLZinf
39907isefXHJrWJtE/4sy8bnW4NbiZKxMFdNteDxrTyUElb59iaxqXXoXoiA5ocv+Y4FP+A0LcLJDp+o
3991SLvZhiPvopXF7y5StZ2C30UlPWqYVujmYZnhOuEWFNemPLbBEF/VyilFO3KLT/BTXw+WZSf4UhYk
39926GF9Hd21fB5/19p1j8Cu3Jy99NbuX79waaDH7ueXIRqwC6oJ8aCKTovR9F8juhN9LDic3tCfpX09
3993HGc5iAc1ahPNkptk7n7Hw+lDfrtcWx/oXI5wd72zpr3Xhg079zm5z818EIfP7f03Ol1daPZig0Xv
3994Gplyvc5UrlZqmuCraqbk5dDZcs98Gbv5ll5TIhO1M+YOb9QDCMMqugrILfSDXQdPil+Zx0ezztVp
3995QVNTAZNTEaXSBUev2rYCuJijVhpvkiJc0hRmEvMNqqnKCtyRUL9Yjc8Mh8qsWqAmgtok6tqgbkZM
39969Hu2cAo+qDbXbzhWZhfHow4Qgqvynfd2cI3gdGrbgF+etRcB04llCJk3G4iP6/YOvH82kYpvnRno
39970hVusBMjtWLX4RQXsdTyh4MURin2+xfa/HvezR23/8ZWpT2crWiEDr8fc7HQkXLDzemtfSmM++6F
3998Bb2vjyIifneCsN1a7rP3/mEr/qpf+kCKUAct3KpfMsEvzuKsClZkOXwEcu9eefAr46zOYofBouE8
3999cxVD/60CeGuODO3Q23N6XNB/T47PDO38vt6wzNLLRO/pbKl4wj0GFU8727h15bGI5R5X3i9UfKQr
400078F/oCuv33UE1kTjo/XBYOniPT4/qwn3xUEtI8CYKRAJk+2dt+wYezhyCwHBIU9vQ/uWPNaZzu0C
4001YyaQI/sv0CAQP3Dljls15b2vxMw75Gv70kWPv7t4/+r0gmgx/XD6+j9Pv6MjYsxbdWzWg2OdvDhk
4002ah96JWlu3KOP9YYmb7EdeGcW11VrCL323pHIAIThGvqhDe0qMrd534BeLXJ/ECB+97I7UPep7EHI
4003PedL1726h3md2rFAP+VCH/PLOZcxj0zWlMWhTYma9jaLpWW0F+Tv2zin5KavTrRTql9VtScBMbaF
4004X7QDmLxC/rK5K1PFazMk7Kh0311M1Wp4A8Lc8wYpnEvndUP0piEGVfsvSa5A2SWYg2eHcWJfOEj9
4005OE+n7Js0MQ8/l7EhiHcFIeyvzxX2hcz2UCEIWOHpl+kwIkb/6cy2PQ16osTlIV12OkRlc2V/4Z5p
4006J/fnFM98avtWCmWOSzHfDZ2XTeae49gxvQHk/FFasFg61bWg+Y6Azq14KmBv9JlYIc52IoIoUR9W
4007YMEO0VG/UcZBHu2mg72h1TNxuO8qjHsVRIjn+zsuOrdN9IgXPELdM0I15sKBY4GxZmTfHRfxLUHm
4008vLKg11B4zgeeZ+iX/MHXm8vnxzYpifyOze5LDpD2oWPYL9uq8jtffOSMJl6pJlQ7gIUq4y74q9Bh
4009zaXYH+D0amT3BEHmwIkhhV778Lm6GeG9TDTsImr57hgWJEZP1JgW5VQVa9ztk3Fvsa3K6sPgAun7
4010YfS0H4BCKMO+CX74XRugnp/peHDW0NvirMOJ1wodeaBDcp8XeITx+lrsusPpWtODhlO5uC0y5w5d
40113tP7DWLNXgP38hId+21Bd+UtD+yx/XxBbHj88weM75dT2OEv7nKoba8vBy8lsBOLBTh4PNuhkHkc
4012g3UBhTkiNY21m0bC8eJ3S0aHm9qlIVegw0c1PfgmSAosyImdastvjUHwfz3zySQ=
4013""".decode("base64").decode("zlib")
4014
4015##file ez_setup.py
4016EZ_SETUP_PY = """
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
4083178BYnMUkw==
4084""".decode("base64").decode("zlib")
4085
4086##file distribute_setup.py
4087DISTRIBUTE_SETUP_PY = """
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
4165""".decode("base64").decode("zlib")
4166
4167##file activate.sh
4168ACTIVATE_SH = """
4169eJytU11P2zAUffevuKQ8AFqJ+srUh6IhgcTKRFgnjSLXTW4aS6ld2U6zgvbfd50PSD+GNI08JLHv
41708fW5557bg4dMWkhljrAsrIM5QmExgVK6DAKrCxMjzKUKRezkWjgM4Cw1eglzYbMz1oONLiAWSmkH
4171plAgHSTSYOzyDWMJtqfg5BReGNAjU3iEvoLgmN/dfuGTm/uH76Nb/m30cB3AE3wGl6GqkP7x28ND
41720FcE/lpp4yrg616hLDrYO1TFU8mqb6+u3Ga6yBNI0BHnqigQKoFnm32CMpNxBplYIwj6UCjWy6UP
4173u0y4Sq8mFakWizwn3ZyGBd1NMtBfqo1frAQJ2xy15wA/SFtduCbspFo0abaAXgg49rwhzoRaoIWS
4174miQS/9qAF5yuNWhXxByTHXEvRxHp2df16md0zSdX99HN3fiAyFVpfbMlz9/aFA0OdSka7DWJgHs9
4175igbvtqgJtxRqSBu9Gk/eiB0RLyIyhEBplaB1pvBGwx1uPYgwT6EFHO3c3veh1qHt1b8ZmbqOS2Mw
4176p+4rB2thpJjnaLue3r6bsQ7VYcB5Z8l5wBoRuvWwPYuSjLW9m0UHHXJ+eTPm49HXK84vGljX/WxX
4177TZ/Mt6GSLJiRuVGJJcJ0K+80mFVKEsdd9by1pMjJ2xa9W2FEO4rst5BxM+baSBKlgSNC5tzqIgzL
4178sjx/RkdmXZ+ToUOrU1cKg6HwGUL26prHDq0ZpTxIcDqbPUFdC+YW306fvFPUaX2AWtqxH/ugsf+A
4179kf/Pcf/3UW/HnBT5Axjqy2Y=
4180""".decode("base64").decode("zlib")
4181
4182##file activate.bat
4183ACTIVATE_BAT = """
4184eJx9kMsOgjAQRfdN+g+zoAn8goZEDESJPBpEViSzkFbZ0IX8f+RRaVW0u5mee3PanbjeFSgpKXmI
4185Hqq4KC9BglFW+YjWhEgJJa2ETvXQCNl2ogFe5CkvwaUEhjPm543vcOdAiacjLxzzJFw6f2bZCsZ0
41862YitXPtswawi1zwgC9II0QPD/RELyuOb1jB/Sg0rNhM31Ss4n2I+7ibLb8epQGco2Rja1Fs/zeoa
4187cR9nWnprJaMspOQJdBR1/g==
4188""".decode("base64").decode("zlib")
4189
4190##file deactivate.bat
4191DEACTIVATE_BAT = """
4192eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q
4193FlWqXJpcICVYpGzx2OAY4oFsPpCLbjpQCLvZILVcXFaufi5cACHzOrI=
4194""".decode("base64").decode("zlib")
4195
4196##file distutils-init.py
4197DISTUTILS_INIT = """
4198eJytVl2L6zYQffevGBKK7XavKe3bhVBo78uFSyml0IdlEVpbTtR1JCMpm6S/vjOSY0v+uO1DDbs4
41990tF8nJk5sjz32jjQNpPhzd7H1ys3SqqjhcfCL1q18vgbN1YY2Kc/pQWlHXB4l8ZdeCfUO5x1c+nE
4200E1gNVwE1V3CxAqQDp6GVqgF3EmBd08nXLGukUfws4IDBVD13p2pYoS3rLk52ltF6hPhLS1XM4EUc
4201VsVYKzvBWPkE+WgmLzPZjkaUNmd6KVI3JRwWoRSLM6P98mMG+Dw4q+il8Ev07P7ATCNmRlfQ8/qN
4202HwVwB99Y4H0vMHAi6BWZUoEhoqXTNXdSK+A2LN6tE+fJ0E+7MhOdFSEM5lNgrJIKWXDF908wy87D
4203xE3UoHsxkegZTaHIHGNSSYfm+ntelpURvCnK7NEWBI/ap/b8Z1m232N2rj7B60V2DRM3B5NpaLSw
4204KnfwpvQVTviHOR+F88lhQyBAGlE7be6DoRNg9ldsG3218IHa6MRNU+tGBEYIggwafRk6yzsXDcVU
42059Ua08kYxt+F3x12LRaQi52j0xx/ywFxrdMRqVevzmaummlIYEp0WsCAaX8cFb6buuLUTqEgQQ6/Q
420604iWRoF38m/BdE8VtlBY0bURiB6KG1crpMZwc2fIjqWh+1UrkSLpWUIP8PySwLKv4qPGSVqDuMPy
4207dywQ+gS7L1irXVkm5pJsq3l+Ib1lMOvUrxI+/mBBY4KB+WpUtcO06RtzckNvQ6vYj1lGoZM2sdDG
4208fryJPYJVn/Cfka8XSqNaoLKhmOlqXMzW9+YBVp1EtIThZtOwzCRvMaARa+0xD0b2kcaJGwJsMbc7
4209hLUfY4vKvsCOBdvDnyfuRbzmXRdGTZgPF7oGQkJACWVD22IMQdhx0npt5S2f+pXO+OwH6d+hwiS5
42107IJOjcK2emj1zBy1aONHByfAMoraw6WlrSIFTbGghqASoRCjVncYROFpXM4uYSqhGnuVeGvks4jz
4211cjnCoR5GnPW7KOh4maVbdFeoplgJ3wh3MSrAsv/QuMjOspnTKRl1fTYqqNisv7uTVnhF1GhoBFbp
4212lh+OcXN2riA5ZrYXtWxlfcDuC8U5kLoN3CCJYXGpesO6dx6rU0zGMtjU6cNlmW0Fid8Sja4ZG+Z3
4213fTPbyj+mZnZ2wSQK8RaT9Km0ySRuLpm0DkUUL0ra3WQ2BgGJ7v9I9SKqNKZ/IR4R28RHm+vEz5ic
4214nZ2IH7bfub8pU1PR3gr10W7xLTfHh6Z6bgZ7K14G7Mj/1z5J6MFo6V5e07H0Ou78dTyeI+mxKOpI
4215eC2KMSj6HKxd6Uudf/n886fPv+f++x1lbASlmjQuPz8OvGA0j7j2eCu/4bcW6SFeCuNJ0W1GQHI5
4216iwC9Ey0bjtHd9P4dPA++XxLnZDVuxvFEtlm3lf5a2c02u2LRYXHH/AOs8pIa
4217""".decode("base64").decode("zlib")
4218
4219##file distutils.cfg
4220DISTUTILS_CFG = """
4221eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH
4222xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg
42239FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q=
4224""".decode("base64").decode("zlib")
4225
4226##file activate_this.py
4227ACTIVATE_THIS = """
4228eJx1UsGOnDAMvecrIlYriDRlKvU20h5aaY+teuilGo1QALO4CwlKAjP8fe1QGGalRoLEefbzs+Mk
4229Sb7NcvRo3iTcoGqwgyy06As+HWSNVciKaBTFywYoJWc7yit2ndBVwEkHkIzKCV0YdQdmkvShs6YH
4230E3IhfjFaaSNLoHxQy2sLJrL0ow98JQmEG/rAYn7OobVGogngBgf0P0hjgwgt7HOUaI5DdBVJkggR
42313HwSktaqWcCtgiHIH7qHV+esW2CnkRJ+9R5cQGsikkWEV/J7leVGs9TV4TvcO5QOOrTHYI+xeCjY
4232JR/m9GPDHv2oSZunUokS2A/WBelnvx6tF6LUJO2FjjlH5zU6Q+Kz/9m69LxvSZVSwiOlGnT1rt/A
423377j+WDQZ8x9k2mFJetOle88+lc8sJJ/AeerI+fTlQigTfVqJUiXoKaaC3AqmI+KOnivjMLbvBVFU
42341JDruuadNGcPmkgiBTnQXUGUDd6IK9JEQ9yPdM96xZP8bieeMRqTuqbxIbbey2DjVUNzRs1rosFS
4235TsLAdS/0fBGNdTGKhuqD7mUmsFlgGjN2eSj1tM3GnjfXwwCmzjhMbR4rLZXXk+Z/6Hp7Pn2+kJ49
4236jfgLHgI4Jg==
4237""".decode("base64").decode("zlib")
4238
4239if __name__ == '__main__':
4240    main()
4241
4242# pyutilib.virtualenv: ignoring comment
4243## Copy python.exe.manifest
4244## Monkeypatch distutils.sysconfig
Note: See TracBrowser for help on using the repository browser.