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