PageRenderTime 295ms CodeModel.GetById 120ms app.highlight 15ms RepoModel.GetById 156ms app.codeStats 0ms

/Lib/distutils/command/install_lib.py

http://unladen-swallow.googlecode.com/
Python | 224 lines | 144 code | 40 blank | 40 comment | 27 complexity | 482a53ba450fb9dbb3417ca1c56d9a4d MD5 | raw file
  1# This module should be kept compatible with Python 2.1.
  2
  3__revision__ = "$Id: install_lib.py 72578 2009-05-12 07:04:51Z tarek.ziade $"
  4
  5import os
  6from types import IntType
  7from distutils.core import Command
  8from distutils.errors import DistutilsOptionError
  9
 10
 11# Extension for Python source files.
 12if hasattr(os, 'extsep'):
 13    PYTHON_SOURCE_EXTENSION = os.extsep + "py"
 14else:
 15    PYTHON_SOURCE_EXTENSION = ".py"
 16
 17class install_lib (Command):
 18
 19    description = "install all Python modules (extensions and pure Python)"
 20
 21    # The byte-compilation options are a tad confusing.  Here are the
 22    # possible scenarios:
 23    #   1) no compilation at all (--no-compile --no-optimize)
 24    #   2) compile .pyc only (--compile --no-optimize; default)
 25    #   3) compile .pyc and "level 1" .pyo (--compile --optimize)
 26    #   4) compile "level 1" .pyo only (--no-compile --optimize)
 27    #   5) compile .pyc and "level 2" .pyo (--compile --optimize-more)
 28    #   6) compile "level 2" .pyo only (--no-compile --optimize-more)
 29    #
 30    # The UI for this is two option, 'compile' and 'optimize'.
 31    # 'compile' is strictly boolean, and only decides whether to
 32    # generate .pyc files.  'optimize' is three-way (0, 1, or 2), and
 33    # decides both whether to generate .pyo files and what level of
 34    # optimization to use.
 35
 36    user_options = [
 37        ('install-dir=', 'd', "directory to install to"),
 38        ('build-dir=','b', "build directory (where to install from)"),
 39        ('force', 'f', "force installation (overwrite existing files)"),
 40        ('compile', 'c', "compile .py to .pyc [default]"),
 41        ('no-compile', None, "don't compile .py files"),
 42        ('optimize=', 'O',
 43         "also compile with optimization: -O1 for \"python -O\", "
 44         "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
 45        ('skip-build', None, "skip the build steps"),
 46        ]
 47
 48    boolean_options = ['force', 'compile', 'skip-build']
 49    negative_opt = {'no-compile' : 'compile'}
 50
 51
 52    def initialize_options (self):
 53        # let the 'install' command dictate our installation directory
 54        self.install_dir = None
 55        self.build_dir = None
 56        self.force = 0
 57        self.compile = None
 58        self.optimize = None
 59        self.skip_build = None
 60
 61    def finalize_options (self):
 62
 63        # Get all the information we need to install pure Python modules
 64        # from the umbrella 'install' command -- build (source) directory,
 65        # install (target) directory, and whether to compile .py files.
 66        self.set_undefined_options('install',
 67                                   ('build_lib', 'build_dir'),
 68                                   ('install_lib', 'install_dir'),
 69                                   ('force', 'force'),
 70                                   ('compile', 'compile'),
 71                                   ('optimize', 'optimize'),
 72                                   ('skip_build', 'skip_build'),
 73                                  )
 74
 75        if self.compile is None:
 76            self.compile = 1
 77        if self.optimize is None:
 78            self.optimize = 0
 79
 80        if type(self.optimize) is not IntType:
 81            try:
 82                self.optimize = int(self.optimize)
 83                if self.optimize not in (0, 1, 2):
 84                    raise AssertionError
 85            except (ValueError, AssertionError):
 86                raise DistutilsOptionError, "optimize must be 0, 1, or 2"
 87
 88    def run (self):
 89
 90        # Make sure we have built everything we need first
 91        self.build()
 92
 93        # Install everything: simply dump the entire contents of the build
 94        # directory to the installation directory (that's the beauty of
 95        # having a build directory!)
 96        outfiles = self.install()
 97
 98        # (Optionally) compile .py to .pyc
 99        if outfiles is not None and self.distribution.has_pure_modules():
100            self.byte_compile(outfiles)
101
102    # run ()
103
104
105    # -- Top-level worker functions ------------------------------------
106    # (called from 'run()')
107
108    def build (self):
109        if not self.skip_build:
110            if self.distribution.has_pure_modules():
111                self.run_command('build_py')
112            if self.distribution.has_ext_modules():
113                self.run_command('build_ext')
114
115    def install (self):
116        if os.path.isdir(self.build_dir):
117            outfiles = self.copy_tree(self.build_dir, self.install_dir)
118        else:
119            self.warn("'%s' does not exist -- no Python modules to install" %
120                      self.build_dir)
121            return
122        return outfiles
123
124    def byte_compile (self, files):
125        from distutils.util import byte_compile
126
127        # Get the "--root" directory supplied to the "install" command,
128        # and use it as a prefix to strip off the purported filename
129        # encoded in bytecode files.  This is far from complete, but it
130        # should at least generate usable bytecode in RPM distributions.
131        install_root = self.get_finalized_command('install').root
132
133        if self.compile:
134            byte_compile(files, optimize=0,
135                         force=self.force, prefix=install_root,
136                         dry_run=self.dry_run)
137        if self.optimize > 0:
138            byte_compile(files, optimize=self.optimize,
139                         force=self.force, prefix=install_root,
140                         verbose=self.verbose, dry_run=self.dry_run)
141
142
143    # -- Utility methods -----------------------------------------------
144
145    def _mutate_outputs (self, has_any, build_cmd, cmd_option, output_dir):
146
147        if not has_any:
148            return []
149
150        build_cmd = self.get_finalized_command(build_cmd)
151        build_files = build_cmd.get_outputs()
152        build_dir = getattr(build_cmd, cmd_option)
153
154        prefix_len = len(build_dir) + len(os.sep)
155        outputs = []
156        for file in build_files:
157            outputs.append(os.path.join(output_dir, file[prefix_len:]))
158
159        return outputs
160
161    # _mutate_outputs ()
162
163    def _bytecode_filenames (self, py_filenames):
164        bytecode_files = []
165        for py_file in py_filenames:
166            # Since build_py handles package data installation, the
167            # list of outputs can contain more than just .py files.
168            # Make sure we only report bytecode for the .py files.
169            ext = os.path.splitext(os.path.normcase(py_file))[1]
170            if ext != PYTHON_SOURCE_EXTENSION:
171                continue
172            if self.compile:
173                bytecode_files.append(py_file + "c")
174            if self.optimize > 0:
175                bytecode_files.append(py_file + "o")
176
177        return bytecode_files
178
179
180    # -- External interface --------------------------------------------
181    # (called by outsiders)
182
183    def get_outputs (self):
184        """Return the list of files that would be installed if this command
185        were actually run.  Not affected by the "dry-run" flag or whether
186        modules have actually been built yet.
187        """
188        pure_outputs = \
189            self._mutate_outputs(self.distribution.has_pure_modules(),
190                                 'build_py', 'build_lib',
191                                 self.install_dir)
192        if self.compile:
193            bytecode_outputs = self._bytecode_filenames(pure_outputs)
194        else:
195            bytecode_outputs = []
196
197        ext_outputs = \
198            self._mutate_outputs(self.distribution.has_ext_modules(),
199                                 'build_ext', 'build_lib',
200                                 self.install_dir)
201
202        return pure_outputs + bytecode_outputs + ext_outputs
203
204    # get_outputs ()
205
206    def get_inputs (self):
207        """Get the list of files that are input to this command, ie. the
208        files that get installed as they are named in the build tree.
209        The files in this list correspond one-to-one to the output
210        filenames returned by 'get_outputs()'.
211        """
212        inputs = []
213
214        if self.distribution.has_pure_modules():
215            build_py = self.get_finalized_command('build_py')
216            inputs.extend(build_py.get_outputs())
217
218        if self.distribution.has_ext_modules():
219            build_ext = self.get_finalized_command('build_ext')
220            inputs.extend(build_ext.get_outputs())
221
222        return inputs
223
224# class install_lib