1 # This module should be kept compatible with Python 1.5.2.
6 from types
import IntType
7 from distutils
.core
import Command
8 from distutils
.errors
import DistutilsOptionError
10 class install_lib (Command
):
12 description
= "install all Python modules (extensions and pure Python)"
14 # The byte-compilation options are a tad confusing. Here are the
16 # 1) no compilation at all (--no-compile --no-optimize)
17 # 2) compile .pyc only (--compile --no-optimize; default)
18 # 3) compile .pyc and "level 1" .pyo (--compile --optimize)
19 # 4) compile "level 1" .pyo only (--no-compile --optimize)
20 # 5) compile .pyc and "level 2" .pyo (--compile --optimize-more)
21 # 6) compile "level 2" .pyo only (--no-compile --optimize-more)
23 # The UI for this is two option, 'compile' and 'optimize'.
24 # 'compile' is strictly boolean, and only decides whether to
25 # generate .pyc files. 'optimize' is three-way (0, 1, or 2), and
26 # decides both whether to generate .pyo files and what level of
27 # optimization to use.
30 ('install-dir=', 'd', "directory to install to"),
31 ('build-dir=','b', "build directory (where to install from)"),
32 ('force', 'f', "force installation (overwrite existing files)"),
33 ('compile', 'c', "compile .py to .pyc [default]"),
34 ('no-compile', None, "don't compile .py files"),
36 "also compile with optimization: -O1 for \"python -O\", "
37 "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
38 ('skip-build', None, "skip the build steps"),
41 boolean_options
= ['force', 'compile', 'skip-build']
42 negative_opt
= {'no-compile' : 'compile'}
45 def initialize_options (self
):
46 # let the 'install' command dictate our installation directory
47 self
.install_dir
= None
52 self
.skip_build
= None
54 def finalize_options (self
):
56 # Get all the information we need to install pure Python modules
57 # from the umbrella 'install' command -- build (source) directory,
58 # install (target) directory, and whether to compile .py files.
59 self
.set_undefined_options('install',
60 ('build_lib', 'build_dir'),
61 ('install_lib', 'install_dir'),
63 ('compile', 'compile'),
64 ('optimize', 'optimize'),
65 ('skip_build', 'skip_build'),
68 if self
.compile is None:
70 if self
.optimize
is None:
73 if type(self
.optimize
) is not IntType
:
75 self
.optimize
= int(self
.optimize
)
76 assert 0 <= self
.optimize
<= 2
77 except (ValueError, AssertionError):
78 raise DistutilsOptionError
, "optimize must be 0, 1, or 2"
82 # Make sure we have built everything we need first
85 # Install everything: simply dump the entire contents of the build
86 # directory to the installation directory (that's the beauty of
87 # having a build directory!)
88 outfiles
= self
.install()
90 # (Optionally) compile .py to .pyc
91 if outfiles
is not None and self
.distribution
.has_pure_modules():
92 self
.byte_compile(outfiles
)
97 # -- Top-level worker functions ------------------------------------
98 # (called from 'run()')
101 if not self
.skip_build
:
102 if self
.distribution
.has_pure_modules():
103 self
.run_command('build_py')
104 if self
.distribution
.has_ext_modules():
105 self
.run_command('build_ext')
108 if os
.path
.isdir(self
.build_dir
):
109 outfiles
= self
.copy_tree(self
.build_dir
, self
.install_dir
)
111 self
.warn("'%s' does not exist -- no Python modules to install" %
116 def byte_compile (self
, files
):
117 from distutils
.util
import byte_compile
119 # Get the "--root" directory supplied to the "install" command,
120 # and use it as a prefix to strip off the purported filename
121 # encoded in bytecode files. This is far from complete, but it
122 # should at least generate usable bytecode in RPM distributions.
123 install_root
= self
.get_finalized_command('install').root
126 byte_compile(files
, optimize
=0,
127 force
=self
.force
, prefix
=install_root
,
128 dry_run
=self
.dry_run
)
129 if self
.optimize
> 0:
130 byte_compile(files
, optimize
=self
.optimize
,
131 force
=self
.force
, prefix
=install_root
,
132 verbose
=self
.verbose
, dry_run
=self
.dry_run
)
135 # -- Utility methods -----------------------------------------------
137 def _mutate_outputs (self
, has_any
, build_cmd
, cmd_option
, output_dir
):
142 build_cmd
= self
.get_finalized_command(build_cmd
)
143 build_files
= build_cmd
.get_outputs()
144 build_dir
= getattr(build_cmd
, cmd_option
)
146 prefix_len
= len(build_dir
) + len(os
.sep
)
148 for file in build_files
:
149 outputs
.append(os
.path
.join(output_dir
, file[prefix_len
:]))
155 def _bytecode_filenames (self
, py_filenames
):
157 for py_file
in py_filenames
:
159 bytecode_files
.append(py_file
+ "c")
160 if self
.optimize
> 0:
161 bytecode_files
.append(py_file
+ "o")
163 return bytecode_files
166 # -- External interface --------------------------------------------
167 # (called by outsiders)
169 def get_outputs (self
):
170 """Return the list of files that would be installed if this command
171 were actually run. Not affected by the "dry-run" flag or whether
172 modules have actually been built yet.
175 self
._mutate
_outputs
(self
.distribution
.has_pure_modules(),
176 'build_py', 'build_lib',
179 bytecode_outputs
= self
._bytecode
_filenames
(pure_outputs
)
181 bytecode_outputs
= []
184 self
._mutate
_outputs
(self
.distribution
.has_ext_modules(),
185 'build_ext', 'build_lib',
188 return pure_outputs
+ bytecode_outputs
+ ext_outputs
192 def get_inputs (self
):
193 """Get the list of files that are input to this command, ie. the
194 files that get installed as they are named in the build tree.
195 The files in this list correspond one-to-one to the output
196 filenames returned by 'get_outputs()'.
200 if self
.distribution
.has_pure_modules():
201 build_py
= self
.get_finalized_command('build_py')
202 inputs
.extend(build_py
.get_outputs())
204 if self
.distribution
.has_ext_modules():
205 build_ext
= self
.get_finalized_command('build_ext')
206 inputs
.extend(build_ext
.get_outputs())