build_py.py revision e557f3556f1f87825e00a018eabf837c4c55f7d5
113ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward"""distutils.command.build_py 213ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 313ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg WardImplements the Distutils 'build_py' command.""" 413ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 5d448f66317130555cfc157683c743b3d004374c4Andrew M. Kuchling# This module should be kept compatible with Python 1.5.2. 6d448f66317130555cfc157683c743b3d004374c4Andrew M. Kuchling 73ce77fd05ed00168f618b63401d770ccc4f04b09Greg Ward__revision__ = "$Id$" 813ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 99b45443c1bdf99b0f27b12baf06fea475b60e145Greg Wardimport sys, string, os 1017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Wardfrom types import * 1117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Wardfrom glob import glob 1217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 1313ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Wardfrom distutils.core import Command 1413ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Wardfrom distutils.errors import * 150c350bfad0ec9350aec57e37962b1aadb8492173Thomas Hellerfrom distutils.util import convert_path 16cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hyltonfrom distutils import log 1713ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 181993f9ad0e2cf53c8dc441cbbb44eb2e3a190538Greg Wardclass build_py (Command): 1913ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 2037bc81505379facad85a7c6ff273de0201f28656Greg Ward description = "\"build\" pure Python modules (copy to build directory)" 2137bc81505379facad85a7c6ff273de0201f28656Greg Ward 22bbeceeaf9a5edf878154b17a6a94403a26822d51Greg Ward user_options = [ 23e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward ('build-lib=', 'd', "directory to \"build\" (copy) to"), 2473a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward ('compile', 'c', "compile .py to .pyc"), 2573a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward ('no-compile', None, "don't compile .py files [default]"), 2673a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward ('optimize=', 'O', 2773a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward "also compile with optimization: -O1 for \"python -O\", " 2873a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), 296a2035d76ba9572ccd2ed61d59df46e2bdcb74edGreg Ward ('force', 'f', "forcibly build everything (ignore file timestamps)"), 30bbeceeaf9a5edf878154b17a6a94403a26822d51Greg Ward ] 3113ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 3273a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward boolean_options = ['compile', 'force'] 3373a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward negative_opt = {'no-compile' : 'compile'} 3499b032eaf24e1887f6451eceea7f1e24ced05a0fGreg Ward 3513ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 36e01149cbe83778a5cf872a6b429ff33179b7cdcbGreg Ward def initialize_options (self): 37e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward self.build_lib = None 386f980b59368c022fe7c1925e83f909dabf74e634Greg Ward self.py_modules = None 3971eb8644d7e27fd379a2cf78c509155bdb179332Greg Ward self.package = None 4017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.package_dir = None 4173a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward self.compile = 0 4273a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward self.optimize = 0 43c41d6b35a9de3dd9e3057a0db9a83b182e792f79Greg Ward self.force = None 4413ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 45e01149cbe83778a5cf872a6b429ff33179b7cdcbGreg Ward def finalize_options (self): 46cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward self.set_undefined_options('build', 47cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward ('build_lib', 'build_lib'), 48cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward ('force', 'force')) 4917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 5017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Get the distribution options that are aliases for build_py 5117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # options -- list of packages and list of modules. 5217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.packages = self.distribution.packages 536f980b59368c022fe7c1925e83f909dabf74e634Greg Ward self.py_modules = self.distribution.py_modules 540c350bfad0ec9350aec57e37962b1aadb8492173Thomas Heller self.package_dir = {} 550c350bfad0ec9350aec57e37962b1aadb8492173Thomas Heller if self.distribution.package_dir: 560c350bfad0ec9350aec57e37962b1aadb8492173Thomas Heller for name, path in self.distribution.package_dir.items(): 570c350bfad0ec9350aec57e37962b1aadb8492173Thomas Heller self.package_dir[name] = convert_path(path) 5813ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 5973a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward # Ick, copied straight from install_lib.py (fancy_getopt needs a 6073a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward # type system! Hell, *everything* needs a type system!!!) 6173a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward if type(self.optimize) is not IntType: 6273a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward try: 6373a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward self.optimize = int(self.optimize) 6473a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward assert 0 <= self.optimize <= 2 6573a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward except (ValueError, AssertionError): 6673a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward raise DistutilsOptionError, "optimize must be 0, 1, or 2" 6713ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 6813ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward def run (self): 6913ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 709b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # XXX copy_file by default preserves atime and mtime. IMHO this is 719b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # the right thing to do, but perhaps it should be an option -- in 729b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # particular, a site administrator might want installed files to 739b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # reflect the time of installation rather than the last 749b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # modification time before the installed release. 759b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward 769b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # XXX copy_file by default preserves mode, which appears to be the 779b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # wrong thing to do: if a file is read-only in the working 789b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # directory, we want it to be installed read/write so that the next 799b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # installation of the same module distribution can overwrite it 809b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # without problems. (This might be a Unix-specific issue.) Thus 819b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # we turn off 'preserve_mode' when copying to the build directory, 829b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # since the build directory is supposed to be exactly what the 839b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # installation will look like (ie. we preserve mode when 849b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # installing). 8513ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 8617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Two options control which modules will be installed: 'packages' 876f980b59368c022fe7c1925e83f909dabf74e634Greg Ward # and 'py_modules'. The former lets us work with whole packages, not 8817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # specifying individual modules at all; the latter is for 89e557f3556f1f87825e00a018eabf837c4c55f7d5Andrew M. Kuchling # specifying modules one-at-a-time. 90e557f3556f1f87825e00a018eabf837c4c55f7d5Andrew M. Kuchling 916f980b59368c022fe7c1925e83f909dabf74e634Greg Ward if self.py_modules: 92cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward self.build_modules() 93e557f3556f1f87825e00a018eabf837c4c55f7d5Andrew M. Kuchling if self.packages: 94cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward self.build_packages() 9517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 9673a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward self.byte_compile(self.get_outputs(include_bytecode=0)) 9773a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward 9817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # run () 9921d45356b8a22bb3091a97f50b919b57798675f5Fred Drake 10017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 10117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def get_package_dir (self, package): 10217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward """Return the directory, relative to the top of the source 10317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward distribution, where package 'package' should be found 10417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward (at least according to the 'package_dir' option, if any).""" 10517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 106cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward path = string.split(package, '.') 10717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 10817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not self.package_dir: 109631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward if path: 110cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward return apply(os.path.join, path) 111631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward else: 112631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward return '' 11317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 11417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward tail = [] 11517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward while path: 11617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward try: 117cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward pdir = self.package_dir[string.join(path, '.')] 11817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward except KeyError: 119cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward tail.insert(0, path[-1]) 12017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward del path[-1] 12117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 122cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward tail.insert(0, pdir) 123cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward return apply(os.path.join, tail) 12413ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward else: 1258bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # Oops, got all the way through 'path' without finding a 1268bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # match in package_dir. If package_dir defines a directory 1278bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # for the root (nameless) package, then fallback on it; 1288bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # otherwise, we might as well have not consulted 1298bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # package_dir at all, as we just use the directory implied 1308bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # by 'tail' (which should be the same as the original value 1318bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # of 'path' at this point). 1328bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward pdir = self.package_dir.get('') 1338bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward if pdir is not None: 1348bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward tail.insert(0, pdir) 1358bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward 136631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward if tail: 137cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward return apply(os.path.join, tail) 138631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward else: 139631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward return '' 14017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 14117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # get_package_dir () 14217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 14317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 14417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def check_package (self, package, package_dir): 14517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 14617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Empty dir name means current directory, which we can probably 14717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # assume exists. Also, os.path.exists and isdir don't know about 14817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # my "empty string means current dir" convention, so we have to 14917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # circumvent them. 15017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if package_dir != "": 151cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward if not os.path.exists(package_dir): 15217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward raise DistutilsFileError, \ 15317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward "package directory '%s' does not exist" % package_dir 154cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward if not os.path.isdir(package_dir): 15556359f591b361f41f661a14e5ed129bf8f22fa87Greg Ward raise DistutilsFileError, \ 15617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward ("supposed package directory '%s' exists, " + 15717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward "but is not a directory") % package_dir 15817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 15917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Require __init__.py for all but the "root package" 160631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward if package: 161cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward init_py = os.path.join(package_dir, "__init__.py") 162cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward if os.path.isfile(init_py): 1638bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward return init_py 1648bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward else: 165cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hylton log.warn(("package init file '%s' not found " + 166cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hylton "(or not a regular file)"), init_py) 1678bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward 1688bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # Either not in a package at all (__init__.py not expected), or 1698bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # __init__.py doesn't exist -- so don't return the filename. 17011a52708f7f2223b335734e584e2ba30eae74a5fJeremy Hylton return None 17121d45356b8a22bb3091a97f50b919b57798675f5Fred Drake 17217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # check_package () 17317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 17417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 17517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def check_module (self, module, module_file): 176cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward if not os.path.isfile(module_file): 177cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hylton log.warn("file %s (for module %s) not found", module_file, module) 178a863270f0403e537f2de6cc665cf172be673ca48Tim Peters return 0 17917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 180a863270f0403e537f2de6cc665cf172be673ca48Tim Peters return 1 18117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 18217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # check_module () 18317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 18417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 1852a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward def find_package_modules (self, package, package_dir): 186cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward self.check_package(package, package_dir) 187cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward module_files = glob(os.path.join(package_dir, "*.py")) 1888b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward modules = [] 1899821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward setup_script = os.path.abspath(self.distribution.script_name) 1909b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward 19117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward for f in module_files: 192cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward abs_f = os.path.abspath(f) 1939b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward if abs_f != setup_script: 194cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward module = os.path.splitext(os.path.basename(f))[0] 195cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward modules.append((package, module, f)) 1969821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward else: 1979821bf4e62bcb7d503aed782a8f6398e5de720afGreg Ward self.debug_print("excluding %s" % setup_script) 1988b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return modules 19917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 20017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 2012a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward def find_modules (self): 2028bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward """Finds individually-specified Python modules, ie. those listed by 2036f980b59368c022fe7c1925e83f909dabf74e634Greg Ward module name in 'self.py_modules'. Returns a list of tuples (package, 2048bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward module_base, filename): 'package' is a tuple of the path through 2058bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward package-space to the module; 'module_base' is the bare (no 2068bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward packages, no dots) module name, and 'filename' is the path to the 2078bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward ".py" file (relative to the distribution root) that implements the 2088bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward module. 2098bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward """ 2108bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward 21117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Map package names to tuples of useful info about the package: 21217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # (package_dir, checked) 21317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # package_dir - the directory where we'll find source files for 21417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # this package 21517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # checked - true if we have checked that the package directory 21617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # is valid (exists, contains __init__.py, ... ?) 21717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward packages = {} 21817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 2198bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # List of (package, module, filename) tuples to return 2202a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = [] 2212a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 22217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # We treat modules-in-packages almost the same as toplevel modules, 22317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # just the "package" for a toplevel is empty (either an empty 22417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # string or empty list, depending on context). Differences: 22517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # - don't check for __init__.py in directory for empty package 22617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 2276f980b59368c022fe7c1925e83f909dabf74e634Greg Ward for module in self.py_modules: 228cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward path = string.split(module, '.') 229c0fe82ca26b1da22e35f2d0676f09795d052e4f0Greg Ward package = string.join(path[0:-1], '.') 2302a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward module_base = path[-1] 23117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 23217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward try: 23317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward (package_dir, checked) = packages[package] 23417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward except KeyError: 235cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward package_dir = self.get_package_dir(package) 23617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward checked = 0 23717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 23817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not checked: 239cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward init_py = self.check_package(package, package_dir) 24017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward packages[package] = (package_dir, 1) 2418bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward if init_py: 2428bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward modules.append((package, "__init__", init_py)) 24317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 24417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # XXX perhaps we should also check for just .pyc files 24517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # (so greedy closed-source bastards can distribute Python 24617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # modules too) 247cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward module_file = os.path.join(package_dir, module_base + ".py") 248cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward if not self.check_module(module, module_file): 24917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward continue 25017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 251cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward modules.append((package, module_base, module_file)) 2522a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2532a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward return modules 2542a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2552a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # find_modules () 2562a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2572a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2588b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def find_all_modules (self): 2598b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward """Compute the list of all modules that will be built, whether 2606f980b59368c022fe7c1925e83f909dabf74e634Greg Ward they are specified one-module-at-a-time ('self.py_modules') or 2618b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward by whole packages ('self.packages'). Return a list of tuples 2628b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward (package, module, module_file), just like 'find_modules()' and 2638b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 'find_package_modules()' do.""" 2642a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 265e557f3556f1f87825e00a018eabf837c4c55f7d5Andrew M. Kuchling modules = [] 2666f980b59368c022fe7c1925e83f909dabf74e634Greg Ward if self.py_modules: 267e557f3556f1f87825e00a018eabf837c4c55f7d5Andrew M. Kuchling modules.extend(self.find_modules()) 268e557f3556f1f87825e00a018eabf837c4c55f7d5Andrew M. Kuchling if self.packages: 2692a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward for package in self.packages: 270cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward package_dir = self.get_package_dir(package) 271cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward m = self.find_package_modules(package, package_dir) 272cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward modules.extend(m) 2732a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2748b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return modules 2758b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2768b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # find_all_modules () 2778b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2788b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2798b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def get_source_files (self): 2808b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 281cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward modules = self.find_all_modules() 2822a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward filenames = [] 2832a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward for module in modules: 284cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward filenames.append(module[-1]) 2852a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2868b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return filenames 2872a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2882a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2898b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def get_module_outfile (self, build_dir, package, module): 2908b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward outfile_path = [build_dir] + list(package) + [module + ".py"] 291cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward return apply(os.path.join, outfile_path) 2928b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2938b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 29473a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward def get_outputs (self, include_bytecode=1): 295cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward modules = self.find_all_modules() 2968b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward outputs = [] 2978b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward for (package, module, module_file) in modules: 298cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward package = string.split(package, '.') 29973a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward filename = self.get_module_outfile(self.build_lib, package, module) 30073a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward outputs.append(filename) 30173a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward if include_bytecode: 30273a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward if self.compile: 30373a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward outputs.append(filename + "c") 30473a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward if self.optimize > 0: 30573a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward outputs.append(filename + "o") 30673a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward 3078b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return outputs 3082a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 3098b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 3108b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def build_module (self, module, module_file, package): 311cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward if type(package) is StringType: 312cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward package = string.split(package, '.') 313cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward elif type(package) not in (ListType, TupleType): 314631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward raise TypeError, \ 315631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward "'package' must be a string (dot-separated), list, or tuple" 3162a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 3172a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # Now put the module source file into the "build" area -- this is 318e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # easy, we just copy it somewhere under self.build_lib (the build 3192a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # directory for Python source). 320cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward outfile = self.get_module_outfile(self.build_lib, package, module) 321cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward dir = os.path.dirname(outfile) 322cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward self.mkpath(dir) 323cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward return self.copy_file(module_file, outfile, preserve_mode=0) 3242a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 3252a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 3262a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward def build_modules (self): 3272a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 3282a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = self.find_modules() 3298b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward for (package, module, module_file) in modules: 3302a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 33117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Now "build" the module -- ie. copy the source file to 332e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # self.build_lib (the build directory for Python source). 3332a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # (Actually, it gets copied to the directory for this package 334e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # under self.build_lib.) 335cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward self.build_module(module, module_file, package) 33617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 33717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # build_modules () 33817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 33917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 34017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def build_packages (self): 34117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 34217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward for package in self.packages: 3438b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 3448b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # Get list of (package, module, module_file) tuples based on 3458b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # scanning the package directory. 'package' is only included 3468b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # in the tuple so that 'find_modules()' and 3478b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # 'find_package_tuples()' have a consistent interface; it's 3488b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # ignored here (apart from a sanity check). Also, 'module' is 3498b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # the *unqualified* module name (ie. no dots, no package -- we 3508b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # already know its package!), and 'module_file' is the path to 3518b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # the .py file, relative to the current directory 3528b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # (ie. including 'package_dir'). 353cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward package_dir = self.get_package_dir(package) 354cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward modules = self.find_package_modules(package, package_dir) 35517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 35617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Now loop over the modules we found, "building" each one (just 357e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # copy it to self.build_lib). 3588b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward for (package_, module, module_file) in modules: 3598b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward assert package == package_ 360cb1f4c4d33711a964dcd40b32a562e2acf745fc2Greg Ward self.build_module(module, module_file, package) 36117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 36217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # build_packages () 36373a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward 36473a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward 36573a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward def byte_compile (self, files): 36673a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward from distutils.util import byte_compile 36773a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward prefix = self.build_lib 36873a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward if prefix[-1] != os.sep: 36973a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward prefix = prefix + os.sep 37073a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward 37173a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward # XXX this code is essentially the same as the 'byte_compile() 37273a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward # method of the "install_lib" command, except for the determination 37373a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward # of the 'prefix' string. Hmmm. 37473a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward 37573a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward if self.compile: 37673a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward byte_compile(files, optimize=0, 377cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hylton force=self.force, prefix=prefix, dry_run=self.dry_run) 37873a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward if self.optimize > 0: 37973a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward byte_compile(files, optimize=self.optimize, 380cd8a1148e19116db109f27d26c02e1de536dc76eJeremy Hylton force=self.force, prefix=prefix, dry_run=self.dry_run) 38173a6c942cda33c0b6c97a10b7ef5664e043f987fGreg Ward 382fcd974efbb71ab7cb5a75639028508e0195939b8Greg Ward# class build_py 383