0001 # This module should be kept compatible with Python 1.5.2. 0002 0003 __revision__ = "$Id: install_lib.py,v 1.43 2004/07/28 14:55:10 fdrake Exp $" 0004 0005 import sys, os, string 0006 from types import IntType 0007 from distutils.core import Command 0008 from distutils.errors import DistutilsOptionError 0009 0010 0011 # Extension for Python source files. 0012 PYTHON_SOURCE_EXTENSION = os.extsep + "py" 0013 0014 0015 class install_lib (Command): 0016 0017 description = "install all Python modules (extensions and pure Python)" 0018 0019 # The byte-compilation options are a tad confusing. Here are the 0020 # possible scenarios: 0021 # 1) no compilation at all (--no-compile --no-optimize) 0022 # 2) compile .pyc only (--compile --no-optimize; default) 0023 # 3) compile .pyc and "level 1" .pyo (--compile --optimize) 0024 # 4) compile "level 1" .pyo only (--no-compile --optimize) 0025 # 5) compile .pyc and "level 2" .pyo (--compile --optimize-more) 0026 # 6) compile "level 2" .pyo only (--no-compile --optimize-more) 0027 # 0028 # The UI for this is two option, 'compile' and 'optimize'. 0029 # 'compile' is strictly boolean, and only decides whether to 0030 # generate .pyc files. 'optimize' is three-way (0, 1, or 2), and 0031 # decides both whether to generate .pyo files and what level of 0032 # optimization to use. 0033 0034 user_options = [ 0035 ('install-dir=', 'd', "directory to install to"), 0036 ('build-dir=','b', "build directory (where to install from)"), 0037 ('force', 'f', "force installation (overwrite existing files)"), 0038 ('compile', 'c', "compile .py to .pyc [default]"), 0039 ('no-compile', None, "don't compile .py files"), 0040 ('optimize=', 'O', 0041 "also compile with optimization: -O1 for \"python -O\", " 0042 "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), 0043 ('skip-build', None, "skip the build steps"), 0044 ] 0045 0046 boolean_options = ['force', 'compile', 'skip-build'] 0047 negative_opt = {'no-compile' : 'compile'} 0048 0049 0050 def initialize_options (self): 0051 # let the 'install' command dictate our installation directory 0052 self.install_dir = None 0053 self.build_dir = None 0054 self.force = 0 0055 self.compile = None 0056 self.optimize = None 0057 self.skip_build = None 0058 0059 def finalize_options (self): 0060 0061 # Get all the information we need to install pure Python modules 0062 # from the umbrella 'install' command -- build (source) directory, 0063 # install (target) directory, and whether to compile .py files. 0064 self.set_undefined_options('install', 0065 ('build_lib', 'build_dir'), 0066 ('install_lib', 'install_dir'), 0067 ('force', 'force'), 0068 ('compile', 'compile'), 0069 ('optimize', 'optimize'), 0070 ('skip_build', 'skip_build'), 0071 ) 0072 0073 if self.compile is None: 0074 self.compile = 1 0075 if self.optimize is None: 0076 self.optimize = 0 0077 0078 if type(self.optimize) is not IntType: 0079 try: 0080 self.optimize = int(self.optimize) 0081 assert 0 <= self.optimize <= 2 0082 except (ValueError, AssertionError): 0083 raise DistutilsOptionError, "optimize must be 0, 1, or 2" 0084 0085 def run (self): 0086 0087 # Make sure we have built everything we need first 0088 self.build() 0089 0090 # Install everything: simply dump the entire contents of the build 0091 # directory to the installation directory (that's the beauty of 0092 # having a build directory!) 0093 outfiles = self.install() 0094 0095 # (Optionally) compile .py to .pyc 0096 if outfiles is not None and self.distribution.has_pure_modules(): 0097 self.byte_compile(outfiles) 0098 0099 # run () 0100 0101 0102 # -- Top-level worker functions ------------------------------------ 0103 # (called from 'run()') 0104 0105 def build (self): 0106 if not self.skip_build: 0107 if self.distribution.has_pure_modules(): 0108 self.run_command('build_py') 0109 if self.distribution.has_ext_modules(): 0110 self.run_command('build_ext') 0111 0112 def install (self): 0113 if os.path.isdir(self.build_dir): 0114 outfiles = self.copy_tree(self.build_dir, self.install_dir) 0115 else: 0116 self.warn("'%s' does not exist -- no Python modules to install" % 0117 self.build_dir) 0118 return 0119 return outfiles 0120 0121 def byte_compile (self, files): 0122 from distutils.util import byte_compile 0123 0124 # Get the "--root" directory supplied to the "install" command, 0125 # and use it as a prefix to strip off the purported filename 0126 # encoded in bytecode files. This is far from complete, but it 0127 # should at least generate usable bytecode in RPM distributions. 0128 install_root = self.get_finalized_command('install').root 0129 0130 if self.compile: 0131 byte_compile(files, optimize=0, 0132 force=self.force, prefix=install_root, 0133 dry_run=self.dry_run) 0134 if self.optimize > 0: 0135 byte_compile(files, optimize=self.optimize, 0136 force=self.force, prefix=install_root, 0137 verbose=self.verbose, dry_run=self.dry_run) 0138 0139 0140 # -- Utility methods ----------------------------------------------- 0141 0142 def _mutate_outputs (self, has_any, build_cmd, cmd_option, output_dir): 0143 0144 if not has_any: 0145 return [] 0146 0147 build_cmd = self.get_finalized_command(build_cmd) 0148 build_files = build_cmd.get_outputs() 0149 build_dir = getattr(build_cmd, cmd_option) 0150 0151 prefix_len = len(build_dir) + len(os.sep) 0152 outputs = [] 0153 for file in build_files: 0154 outputs.append(os.path.join(output_dir, file[prefix_len:])) 0155 0156 return outputs 0157 0158 # _mutate_outputs () 0159 0160 def _bytecode_filenames (self, py_filenames): 0161 bytecode_files = [] 0162 for py_file in py_filenames: 0163 # Since build_py handles package data installation, the 0164 # list of outputs can contain more than just .py files. 0165 # Make sure we only report bytecode for the .py files. 0166 ext = os.path.splitext(os.path.normcase(py_file))[1] 0167 if ext != PYTHON_SOURCE_EXTENSION: 0168 continue 0169 if self.compile: 0170 bytecode_files.append(py_file + "c") 0171 if self.optimize > 0: 0172 bytecode_files.append(py_file + "o") 0173 0174 return bytecode_files 0175 0176 0177 # -- External interface -------------------------------------------- 0178 # (called by outsiders) 0179 0180 def get_outputs (self): 0181 """Return the list of files that would be installed if this command 0182 were actually run. Not affected by the "dry-run" flag or whether 0183 modules have actually been built yet. 0184 """ 0185 pure_outputs = \ 0186 self._mutate_outputs(self.distribution.has_pure_modules(), 0187 'build_py', 'build_lib', 0188 self.install_dir) 0189 if self.compile: 0190 bytecode_outputs = self._bytecode_filenames(pure_outputs) 0191 else: 0192 bytecode_outputs = [] 0193 0194 ext_outputs = \ 0195 self._mutate_outputs(self.distribution.has_ext_modules(), 0196 'build_ext', 'build_lib', 0197 self.install_dir) 0198 0199 return pure_outputs + bytecode_outputs + ext_outputs 0200 0201 # get_outputs () 0202 0203 def get_inputs (self): 0204 """Get the list of files that are input to this command, ie. the 0205 files that get installed as they are named in the build tree. 0206 The files in this list correspond one-to-one to the output 0207 filenames returned by 'get_outputs()'. 0208 """ 0209 inputs = [] 0210 0211 if self.distribution.has_pure_modules(): 0212 build_py = self.get_finalized_command('build_py') 0213 inputs.extend(build_py.get_outputs()) 0214 0215 if self.distribution.has_ext_modules(): 0216 build_ext = self.get_finalized_command('build_ext') 0217 inputs.extend(build_ext.get_outputs()) 0218 0219 return inputs 0220 0221 # class install_lib 0222
Generated by PyXR 0.9.4