symbian-qemu-0.9.1-12/python-2.6.1/Lib/distutils/command/build_py.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """distutils.command.build_py
       
     2 
       
     3 Implements the Distutils 'build_py' command."""
       
     4 
       
     5 # This module should be kept compatible with Python 2.1.
       
     6 
       
     7 __revision__ = "$Id: build_py.py 65742 2008-08-17 04:16:04Z brett.cannon $"
       
     8 
       
     9 import string, os
       
    10 from types import *
       
    11 from glob import glob
       
    12 
       
    13 from distutils.core import Command
       
    14 from distutils.errors import *
       
    15 from distutils.util import convert_path
       
    16 from distutils import log
       
    17 
       
    18 class 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 = 0
       
   118             if src_dir:
       
   119                 plen = len(src_dir)+1
       
   120 
       
   121             # Strip directory from globbed filenames
       
   122             filenames = [
       
   123                 file[plen:] for file in self.find_data_files(package, src_dir)
       
   124                 ]
       
   125             data.append((package, src_dir, build_dir, filenames))
       
   126         return data
       
   127 
       
   128     def find_data_files (self, package, src_dir):
       
   129         """Return filenames for package's data files in 'src_dir'"""
       
   130         globs = (self.package_data.get('', [])
       
   131                  + self.package_data.get(package, []))
       
   132         files = []
       
   133         for pattern in globs:
       
   134             # Each pattern has to be converted to a platform-specific path
       
   135             filelist = glob(os.path.join(src_dir, convert_path(pattern)))
       
   136             # Files that match more than one pattern are only added once
       
   137             files.extend([fn for fn in filelist if fn not in files])
       
   138         return files
       
   139 
       
   140     def build_package_data (self):
       
   141         """Copy data files into build directory"""
       
   142         lastdir = None
       
   143         for package, src_dir, build_dir, filenames in self.data_files:
       
   144             for filename in filenames:
       
   145                 target = os.path.join(build_dir, filename)
       
   146                 self.mkpath(os.path.dirname(target))
       
   147                 self.copy_file(os.path.join(src_dir, filename), target,
       
   148                                preserve_mode=False)
       
   149 
       
   150     def get_package_dir (self, package):
       
   151         """Return the directory, relative to the top of the source
       
   152            distribution, where package 'package' should be found
       
   153            (at least according to the 'package_dir' option, if any)."""
       
   154 
       
   155         path = string.split(package, '.')
       
   156 
       
   157         if not self.package_dir:
       
   158             if path:
       
   159                 return apply(os.path.join, path)
       
   160             else:
       
   161                 return ''
       
   162         else:
       
   163             tail = []
       
   164             while path:
       
   165                 try:
       
   166                     pdir = self.package_dir[string.join(path, '.')]
       
   167                 except KeyError:
       
   168                     tail.insert(0, path[-1])
       
   169                     del path[-1]
       
   170                 else:
       
   171                     tail.insert(0, pdir)
       
   172                     return os.path.join(*tail)
       
   173             else:
       
   174                 # Oops, got all the way through 'path' without finding a
       
   175                 # match in package_dir.  If package_dir defines a directory
       
   176                 # for the root (nameless) package, then fallback on it;
       
   177                 # otherwise, we might as well have not consulted
       
   178                 # package_dir at all, as we just use the directory implied
       
   179                 # by 'tail' (which should be the same as the original value
       
   180                 # of 'path' at this point).
       
   181                 pdir = self.package_dir.get('')
       
   182                 if pdir is not None:
       
   183                     tail.insert(0, pdir)
       
   184 
       
   185                 if tail:
       
   186                     return apply(os.path.join, tail)
       
   187                 else:
       
   188                     return ''
       
   189 
       
   190     # get_package_dir ()
       
   191 
       
   192 
       
   193     def check_package (self, package, package_dir):
       
   194 
       
   195         # Empty dir name means current directory, which we can probably
       
   196         # assume exists.  Also, os.path.exists and isdir don't know about
       
   197         # my "empty string means current dir" convention, so we have to
       
   198         # circumvent them.
       
   199         if package_dir != "":
       
   200             if not os.path.exists(package_dir):
       
   201                 raise DistutilsFileError, \
       
   202                       "package directory '%s' does not exist" % package_dir
       
   203             if not os.path.isdir(package_dir):
       
   204                 raise DistutilsFileError, \
       
   205                       ("supposed package directory '%s' exists, " +
       
   206                        "but is not a directory") % package_dir
       
   207 
       
   208         # Require __init__.py for all but the "root package"
       
   209         if package:
       
   210             init_py = os.path.join(package_dir, "__init__.py")
       
   211             if os.path.isfile(init_py):
       
   212                 return init_py
       
   213             else:
       
   214                 log.warn(("package init file '%s' not found " +
       
   215                           "(or not a regular file)"), init_py)
       
   216 
       
   217         # Either not in a package at all (__init__.py not expected), or
       
   218         # __init__.py doesn't exist -- so don't return the filename.
       
   219         return None
       
   220 
       
   221     # check_package ()
       
   222 
       
   223 
       
   224     def check_module (self, module, module_file):
       
   225         if not os.path.isfile(module_file):
       
   226             log.warn("file %s (for module %s) not found", module_file, module)
       
   227             return 0
       
   228         else:
       
   229             return 1
       
   230 
       
   231     # check_module ()
       
   232 
       
   233 
       
   234     def find_package_modules (self, package, package_dir):
       
   235         self.check_package(package, package_dir)
       
   236         module_files = glob(os.path.join(package_dir, "*.py"))
       
   237         modules = []
       
   238         setup_script = os.path.abspath(self.distribution.script_name)
       
   239 
       
   240         for f in module_files:
       
   241             abs_f = os.path.abspath(f)
       
   242             if abs_f != setup_script:
       
   243                 module = os.path.splitext(os.path.basename(f))[0]
       
   244                 modules.append((package, module, f))
       
   245             else:
       
   246                 self.debug_print("excluding %s" % setup_script)
       
   247         return modules
       
   248 
       
   249 
       
   250     def find_modules (self):
       
   251         """Finds individually-specified Python modules, ie. those listed by
       
   252         module name in 'self.py_modules'.  Returns a list of tuples (package,
       
   253         module_base, filename): 'package' is a tuple of the path through
       
   254         package-space to the module; 'module_base' is the bare (no
       
   255         packages, no dots) module name, and 'filename' is the path to the
       
   256         ".py" file (relative to the distribution root) that implements the
       
   257         module.
       
   258         """
       
   259 
       
   260         # Map package names to tuples of useful info about the package:
       
   261         #    (package_dir, checked)
       
   262         # package_dir - the directory where we'll find source files for
       
   263         #   this package
       
   264         # checked - true if we have checked that the package directory
       
   265         #   is valid (exists, contains __init__.py, ... ?)
       
   266         packages = {}
       
   267 
       
   268         # List of (package, module, filename) tuples to return
       
   269         modules = []
       
   270 
       
   271         # We treat modules-in-packages almost the same as toplevel modules,
       
   272         # just the "package" for a toplevel is empty (either an empty
       
   273         # string or empty list, depending on context).  Differences:
       
   274         #   - don't check for __init__.py in directory for empty package
       
   275 
       
   276         for module in self.py_modules:
       
   277             path = string.split(module, '.')
       
   278             package = string.join(path[0:-1], '.')
       
   279             module_base = path[-1]
       
   280 
       
   281             try:
       
   282                 (package_dir, checked) = packages[package]
       
   283             except KeyError:
       
   284                 package_dir = self.get_package_dir(package)
       
   285                 checked = 0
       
   286 
       
   287             if not checked:
       
   288                 init_py = self.check_package(package, package_dir)
       
   289                 packages[package] = (package_dir, 1)
       
   290                 if init_py:
       
   291                     modules.append((package, "__init__", init_py))
       
   292 
       
   293             # XXX perhaps we should also check for just .pyc files
       
   294             # (so greedy closed-source bastards can distribute Python
       
   295             # modules too)
       
   296             module_file = os.path.join(package_dir, module_base + ".py")
       
   297             if not self.check_module(module, module_file):
       
   298                 continue
       
   299 
       
   300             modules.append((package, module_base, module_file))
       
   301 
       
   302         return modules
       
   303 
       
   304     # find_modules ()
       
   305 
       
   306 
       
   307     def find_all_modules (self):
       
   308         """Compute the list of all modules that will be built, whether
       
   309         they are specified one-module-at-a-time ('self.py_modules') or
       
   310         by whole packages ('self.packages').  Return a list of tuples
       
   311         (package, module, module_file), just like 'find_modules()' and
       
   312         'find_package_modules()' do."""
       
   313 
       
   314         modules = []
       
   315         if self.py_modules:
       
   316             modules.extend(self.find_modules())
       
   317         if self.packages:
       
   318             for package in self.packages:
       
   319                 package_dir = self.get_package_dir(package)
       
   320                 m = self.find_package_modules(package, package_dir)
       
   321                 modules.extend(m)
       
   322 
       
   323         return modules
       
   324 
       
   325     # find_all_modules ()
       
   326 
       
   327 
       
   328     def get_source_files (self):
       
   329 
       
   330         modules = self.find_all_modules()
       
   331         filenames = []
       
   332         for module in modules:
       
   333             filenames.append(module[-1])
       
   334 
       
   335         return filenames
       
   336 
       
   337 
       
   338     def get_module_outfile (self, build_dir, package, module):
       
   339         outfile_path = [build_dir] + list(package) + [module + ".py"]
       
   340         return os.path.join(*outfile_path)
       
   341 
       
   342 
       
   343     def get_outputs (self, include_bytecode=1):
       
   344         modules = self.find_all_modules()
       
   345         outputs = []
       
   346         for (package, module, module_file) in modules:
       
   347             package = string.split(package, '.')
       
   348             filename = self.get_module_outfile(self.build_lib, package, module)
       
   349             outputs.append(filename)
       
   350             if include_bytecode:
       
   351                 if self.compile:
       
   352                     outputs.append(filename + "c")
       
   353                 if self.optimize > 0:
       
   354                     outputs.append(filename + "o")
       
   355 
       
   356         outputs += [
       
   357             os.path.join(build_dir, filename)
       
   358             for package, src_dir, build_dir, filenames in self.data_files
       
   359             for filename in filenames
       
   360             ]
       
   361 
       
   362         return outputs
       
   363 
       
   364 
       
   365     def build_module (self, module, module_file, package):
       
   366         if type(package) is StringType:
       
   367             package = string.split(package, '.')
       
   368         elif type(package) not in (ListType, TupleType):
       
   369             raise TypeError, \
       
   370                   "'package' must be a string (dot-separated), list, or tuple"
       
   371 
       
   372         # Now put the module source file into the "build" area -- this is
       
   373         # easy, we just copy it somewhere under self.build_lib (the build
       
   374         # directory for Python source).
       
   375         outfile = self.get_module_outfile(self.build_lib, package, module)
       
   376         dir = os.path.dirname(outfile)
       
   377         self.mkpath(dir)
       
   378         return self.copy_file(module_file, outfile, preserve_mode=0)
       
   379 
       
   380 
       
   381     def build_modules (self):
       
   382 
       
   383         modules = self.find_modules()
       
   384         for (package, module, module_file) in modules:
       
   385 
       
   386             # Now "build" the module -- ie. copy the source file to
       
   387             # self.build_lib (the build directory for Python source).
       
   388             # (Actually, it gets copied to the directory for this package
       
   389             # under self.build_lib.)
       
   390             self.build_module(module, module_file, package)
       
   391 
       
   392     # build_modules ()
       
   393 
       
   394 
       
   395     def build_packages (self):
       
   396 
       
   397         for package in self.packages:
       
   398 
       
   399             # Get list of (package, module, module_file) tuples based on
       
   400             # scanning the package directory.  'package' is only included
       
   401             # in the tuple so that 'find_modules()' and
       
   402             # 'find_package_tuples()' have a consistent interface; it's
       
   403             # ignored here (apart from a sanity check).  Also, 'module' is
       
   404             # the *unqualified* module name (ie. no dots, no package -- we
       
   405             # already know its package!), and 'module_file' is the path to
       
   406             # the .py file, relative to the current directory
       
   407             # (ie. including 'package_dir').
       
   408             package_dir = self.get_package_dir(package)
       
   409             modules = self.find_package_modules(package, package_dir)
       
   410 
       
   411             # Now loop over the modules we found, "building" each one (just
       
   412             # copy it to self.build_lib).
       
   413             for (package_, module, module_file) in modules:
       
   414                 assert package == package_
       
   415                 self.build_module(module, module_file, package)
       
   416 
       
   417     # build_packages ()
       
   418 
       
   419 
       
   420     def byte_compile (self, files):
       
   421         from distutils.util import byte_compile
       
   422         prefix = self.build_lib
       
   423         if prefix[-1] != os.sep:
       
   424             prefix = prefix + os.sep
       
   425 
       
   426         # XXX this code is essentially the same as the 'byte_compile()
       
   427         # method of the "install_lib" command, except for the determination
       
   428         # of the 'prefix' string.  Hmmm.
       
   429 
       
   430         if self.compile:
       
   431             byte_compile(files, optimize=0,
       
   432                          force=self.force, prefix=prefix, dry_run=self.dry_run)
       
   433         if self.optimize > 0:
       
   434             byte_compile(files, optimize=self.optimize,
       
   435                          force=self.force, prefix=prefix, dry_run=self.dry_run)
       
   436 
       
   437 # class build_py