Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / v8plus / lib / python2.4 / distutils / command / build_py.py
CommitLineData
920dae64
AT
1"""distutils.command.build_py
2
3Implements the Distutils 'build_py' command."""
4
5# This module should be kept compatible with Python 2.1.
6
7__revision__ = "$Id: build_py.py,v 1.46 2004/11/10 22:23:15 loewis Exp $"
8
9import sys, string, os
10from types import *
11from glob import glob
12
13from distutils.core import Command
14from distutils.errors import *
15from distutils.util import convert_path
16from distutils import log
17
18class build_py (Command):
19
20 description = "\"build\" pure Python modules (copy to build directory)"
21
22 user_options = [
23 ('build-lib=', 'd', "directory to \"build\" (copy) to"),
24 ('compile', 'c', "compile .py to .pyc"),
25 ('no-compile', None, "don't compile .py files [default]"),
26 ('optimize=', 'O',
27 "also compile with optimization: -O1 for \"python -O\", "
28 "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
29 ('force', 'f', "forcibly build everything (ignore file timestamps)"),
30 ]
31
32 boolean_options = ['compile', 'force']
33 negative_opt = {'no-compile' : 'compile'}
34
35
36 def initialize_options (self):
37 self.build_lib = None
38 self.py_modules = None
39 self.package = None
40 self.package_data = None
41 self.package_dir = None
42 self.compile = 0
43 self.optimize = 0
44 self.force = None
45
46 def finalize_options (self):
47 self.set_undefined_options('build',
48 ('build_lib', 'build_lib'),
49 ('force', 'force'))
50
51 # Get the distribution options that are aliases for build_py
52 # options -- list of packages and list of modules.
53 self.packages = self.distribution.packages
54 self.py_modules = self.distribution.py_modules
55 self.package_data = self.distribution.package_data
56 self.package_dir = {}
57 if self.distribution.package_dir:
58 for name, path in self.distribution.package_dir.items():
59 self.package_dir[name] = convert_path(path)
60 self.data_files = self.get_data_files()
61
62 # Ick, copied straight from install_lib.py (fancy_getopt needs a
63 # type system! Hell, *everything* needs a type system!!!)
64 if type(self.optimize) is not IntType:
65 try:
66 self.optimize = int(self.optimize)
67 assert 0 <= self.optimize <= 2
68 except (ValueError, AssertionError):
69 raise DistutilsOptionError, "optimize must be 0, 1, or 2"
70
71 def run (self):
72
73 # XXX copy_file by default preserves atime and mtime. IMHO this is
74 # the right thing to do, but perhaps it should be an option -- in
75 # particular, a site administrator might want installed files to
76 # reflect the time of installation rather than the last
77 # modification time before the installed release.
78
79 # XXX copy_file by default preserves mode, which appears to be the
80 # wrong thing to do: if a file is read-only in the working
81 # directory, we want it to be installed read/write so that the next
82 # installation of the same module distribution can overwrite it
83 # without problems. (This might be a Unix-specific issue.) Thus
84 # we turn off 'preserve_mode' when copying to the build directory,
85 # since the build directory is supposed to be exactly what the
86 # installation will look like (ie. we preserve mode when
87 # installing).
88
89 # Two options control which modules will be installed: 'packages'
90 # and 'py_modules'. The former lets us work with whole packages, not
91 # specifying individual modules at all; the latter is for
92 # specifying modules one-at-a-time.
93
94 if self.py_modules:
95 self.build_modules()
96 if self.packages:
97 self.build_packages()
98 self.build_package_data()
99
100 self.byte_compile(self.get_outputs(include_bytecode=0))
101
102 # run ()
103
104 def get_data_files (self):
105 """Generate list of '(package,src_dir,build_dir,filenames)' tuples"""
106 data = []
107 if not self.packages:
108 return data
109 for package in self.packages:
110 # Locate package source directory
111 src_dir = self.get_package_dir(package)
112
113 # Compute package build directory
114 build_dir = os.path.join(*([self.build_lib] + package.split('.')))
115
116 # Length of path to strip from found files
117 plen = len(src_dir)+1
118
119 # Strip directory from globbed filenames
120 filenames = [
121 file[plen:] for file in self.find_data_files(package, src_dir)
122 ]
123 data.append((package, src_dir, build_dir, filenames))
124 return data
125
126 def find_data_files (self, package, src_dir):
127 """Return filenames for package's data files in 'src_dir'"""
128 globs = (self.package_data.get('', [])
129 + self.package_data.get(package, []))
130 files = []
131 for pattern in globs:
132 # Each pattern has to be converted to a platform-specific path
133 filelist = glob(os.path.join(src_dir, convert_path(pattern)))
134 # Files that match more than one pattern are only added once
135 files.extend([fn for fn in filelist if fn not in files])
136 return files
137
138 def build_package_data (self):
139 """Copy data files into build directory"""
140 lastdir = None
141 for package, src_dir, build_dir, filenames in self.data_files:
142 for filename in filenames:
143 target = os.path.join(build_dir, filename)
144 self.mkpath(os.path.dirname(target))
145 self.copy_file(os.path.join(src_dir, filename), target,
146 preserve_mode=False)
147
148 def get_package_dir (self, package):
149 """Return the directory, relative to the top of the source
150 distribution, where package 'package' should be found
151 (at least according to the 'package_dir' option, if any)."""
152
153 path = string.split(package, '.')
154
155 if not self.package_dir:
156 if path:
157 return apply(os.path.join, path)
158 else:
159 return ''
160 else:
161 tail = []
162 while path:
163 try:
164 pdir = self.package_dir[string.join(path, '.')]
165 except KeyError:
166 tail.insert(0, path[-1])
167 del path[-1]
168 else:
169 tail.insert(0, pdir)
170 return apply(os.path.join, tail)
171 else:
172 # Oops, got all the way through 'path' without finding a
173 # match in package_dir. If package_dir defines a directory
174 # for the root (nameless) package, then fallback on it;
175 # otherwise, we might as well have not consulted
176 # package_dir at all, as we just use the directory implied
177 # by 'tail' (which should be the same as the original value
178 # of 'path' at this point).
179 pdir = self.package_dir.get('')
180 if pdir is not None:
181 tail.insert(0, pdir)
182
183 if tail:
184 return apply(os.path.join, tail)
185 else:
186 return ''
187
188 # get_package_dir ()
189
190
191 def check_package (self, package, package_dir):
192
193 # Empty dir name means current directory, which we can probably
194 # assume exists. Also, os.path.exists and isdir don't know about
195 # my "empty string means current dir" convention, so we have to
196 # circumvent them.
197 if package_dir != "":
198 if not os.path.exists(package_dir):
199 raise DistutilsFileError, \
200 "package directory '%s' does not exist" % package_dir
201 if not os.path.isdir(package_dir):
202 raise DistutilsFileError, \
203 ("supposed package directory '%s' exists, " +
204 "but is not a directory") % package_dir
205
206 # Require __init__.py for all but the "root package"
207 if package:
208 init_py = os.path.join(package_dir, "__init__.py")
209 if os.path.isfile(init_py):
210 return init_py
211 else:
212 log.warn(("package init file '%s' not found " +
213 "(or not a regular file)"), init_py)
214
215 # Either not in a package at all (__init__.py not expected), or
216 # __init__.py doesn't exist -- so don't return the filename.
217 return None
218
219 # check_package ()
220
221
222 def check_module (self, module, module_file):
223 if not os.path.isfile(module_file):
224 log.warn("file %s (for module %s) not found", module_file, module)
225 return 0
226 else:
227 return 1
228
229 # check_module ()
230
231
232 def find_package_modules (self, package, package_dir):
233 self.check_package(package, package_dir)
234 module_files = glob(os.path.join(package_dir, "*.py"))
235 modules = []
236 setup_script = os.path.abspath(self.distribution.script_name)
237
238 for f in module_files:
239 abs_f = os.path.abspath(f)
240 if abs_f != setup_script:
241 module = os.path.splitext(os.path.basename(f))[0]
242 modules.append((package, module, f))
243 else:
244 self.debug_print("excluding %s" % setup_script)
245 return modules
246
247
248 def find_modules (self):
249 """Finds individually-specified Python modules, ie. those listed by
250 module name in 'self.py_modules'. Returns a list of tuples (package,
251 module_base, filename): 'package' is a tuple of the path through
252 package-space to the module; 'module_base' is the bare (no
253 packages, no dots) module name, and 'filename' is the path to the
254 ".py" file (relative to the distribution root) that implements the
255 module.
256 """
257
258 # Map package names to tuples of useful info about the package:
259 # (package_dir, checked)
260 # package_dir - the directory where we'll find source files for
261 # this package
262 # checked - true if we have checked that the package directory
263 # is valid (exists, contains __init__.py, ... ?)
264 packages = {}
265
266 # List of (package, module, filename) tuples to return
267 modules = []
268
269 # We treat modules-in-packages almost the same as toplevel modules,
270 # just the "package" for a toplevel is empty (either an empty
271 # string or empty list, depending on context). Differences:
272 # - don't check for __init__.py in directory for empty package
273
274 for module in self.py_modules:
275 path = string.split(module, '.')
276 package = string.join(path[0:-1], '.')
277 module_base = path[-1]
278
279 try:
280 (package_dir, checked) = packages[package]
281 except KeyError:
282 package_dir = self.get_package_dir(package)
283 checked = 0
284
285 if not checked:
286 init_py = self.check_package(package, package_dir)
287 packages[package] = (package_dir, 1)
288 if init_py:
289 modules.append((package, "__init__", init_py))
290
291 # XXX perhaps we should also check for just .pyc files
292 # (so greedy closed-source bastards can distribute Python
293 # modules too)
294 module_file = os.path.join(package_dir, module_base + ".py")
295 if not self.check_module(module, module_file):
296 continue
297
298 modules.append((package, module_base, module_file))
299
300 return modules
301
302 # find_modules ()
303
304
305 def find_all_modules (self):
306 """Compute the list of all modules that will be built, whether
307 they are specified one-module-at-a-time ('self.py_modules') or
308 by whole packages ('self.packages'). Return a list of tuples
309 (package, module, module_file), just like 'find_modules()' and
310 'find_package_modules()' do."""
311
312 modules = []
313 if self.py_modules:
314 modules.extend(self.find_modules())
315 if self.packages:
316 for package in self.packages:
317 package_dir = self.get_package_dir(package)
318 m = self.find_package_modules(package, package_dir)
319 modules.extend(m)
320
321 return modules
322
323 # find_all_modules ()
324
325
326 def get_source_files (self):
327
328 modules = self.find_all_modules()
329 filenames = []
330 for module in modules:
331 filenames.append(module[-1])
332
333 return filenames
334
335
336 def get_module_outfile (self, build_dir, package, module):
337 outfile_path = [build_dir] + list(package) + [module + ".py"]
338 return apply(os.path.join, outfile_path)
339
340
341 def get_outputs (self, include_bytecode=1):
342 modules = self.find_all_modules()
343 outputs = []
344 for (package, module, module_file) in modules:
345 package = string.split(package, '.')
346 filename = self.get_module_outfile(self.build_lib, package, module)
347 outputs.append(filename)
348 if include_bytecode:
349 if self.compile:
350 outputs.append(filename + "c")
351 if self.optimize > 0:
352 outputs.append(filename + "o")
353
354 outputs += [
355 os.path.join(build_dir, filename)
356 for package, src_dir, build_dir, filenames in self.data_files
357 for filename in filenames
358 ]
359
360 return outputs
361
362
363 def build_module (self, module, module_file, package):
364 if type(package) is StringType:
365 package = string.split(package, '.')
366 elif type(package) not in (ListType, TupleType):
367 raise TypeError, \
368 "'package' must be a string (dot-separated), list, or tuple"
369
370 # Now put the module source file into the "build" area -- this is
371 # easy, we just copy it somewhere under self.build_lib (the build
372 # directory for Python source).
373 outfile = self.get_module_outfile(self.build_lib, package, module)
374 dir = os.path.dirname(outfile)
375 self.mkpath(dir)
376 return self.copy_file(module_file, outfile, preserve_mode=0)
377
378
379 def build_modules (self):
380
381 modules = self.find_modules()
382 for (package, module, module_file) in modules:
383
384 # Now "build" the module -- ie. copy the source file to
385 # self.build_lib (the build directory for Python source).
386 # (Actually, it gets copied to the directory for this package
387 # under self.build_lib.)
388 self.build_module(module, module_file, package)
389
390 # build_modules ()
391
392
393 def build_packages (self):
394
395 for package in self.packages:
396
397 # Get list of (package, module, module_file) tuples based on
398 # scanning the package directory. 'package' is only included
399 # in the tuple so that 'find_modules()' and
400 # 'find_package_tuples()' have a consistent interface; it's
401 # ignored here (apart from a sanity check). Also, 'module' is
402 # the *unqualified* module name (ie. no dots, no package -- we
403 # already know its package!), and 'module_file' is the path to
404 # the .py file, relative to the current directory
405 # (ie. including 'package_dir').
406 package_dir = self.get_package_dir(package)
407 modules = self.find_package_modules(package, package_dir)
408
409 # Now loop over the modules we found, "building" each one (just
410 # copy it to self.build_lib).
411 for (package_, module, module_file) in modules:
412 assert package == package_
413 self.build_module(module, module_file, package)
414
415 # build_packages ()
416
417
418 def byte_compile (self, files):
419 from distutils.util import byte_compile
420 prefix = self.build_lib
421 if prefix[-1] != os.sep:
422 prefix = prefix + os.sep
423
424 # XXX this code is essentially the same as the 'byte_compile()
425 # method of the "install_lib" command, except for the determination
426 # of the 'prefix' string. Hmmm.
427
428 if self.compile:
429 byte_compile(files, optimize=0,
430 force=self.force, prefix=prefix, dry_run=self.dry_run)
431 if self.optimize > 0:
432 byte_compile(files, optimize=self.optimize,
433 force=self.force, prefix=prefix, dry_run=self.dry_run)
434
435# class build_py