build_py.py revision c0fe82ca26b1da22e35f2d0676f09795d052e4f0
113ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward"""distutils.command.build_py 213ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 313ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg WardImplements the Distutils 'build_py' command.""" 413ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 513ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward# created 1999/03/08, Greg Ward 613ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 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 * 1513ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 1613ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 171993f9ad0e2cf53c8dc441cbbb44eb2e3a190538Greg Wardclass build_py (Command): 1813ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 1937bc81505379facad85a7c6ff273de0201f28656Greg Ward description = "\"build\" pure Python modules (copy to build directory)" 2037bc81505379facad85a7c6ff273de0201f28656Greg Ward 21bbeceeaf9a5edf878154b17a6a94403a26822d51Greg Ward user_options = [ 22e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward ('build-lib=', 'd', "directory to \"build\" (copy) to"), 23c41d6b35a9de3dd9e3057a0db9a83b182e792f79Greg Ward ('force', 'f', "forcibly build everything (ignore file timestamps"), 24bbeceeaf9a5edf878154b17a6a94403a26822d51Greg Ward ] 2513ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 2613ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 27e01149cbe83778a5cf872a6b429ff33179b7cdcbGreg Ward def initialize_options (self): 28e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward self.build_lib = None 296f980b59368c022fe7c1925e83f909dabf74e634Greg Ward self.py_modules = None 3071eb8644d7e27fd379a2cf78c509155bdb179332Greg Ward self.package = None 3117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.package_dir = None 32c41d6b35a9de3dd9e3057a0db9a83b182e792f79Greg Ward self.force = None 3313ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 34e01149cbe83778a5cf872a6b429ff33179b7cdcbGreg Ward def finalize_options (self): 3513ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward self.set_undefined_options ('build', 36c41d6b35a9de3dd9e3057a0db9a83b182e792f79Greg Ward ('build_lib', 'build_lib'), 37c41d6b35a9de3dd9e3057a0db9a83b182e792f79Greg Ward ('force', 'force')) 3817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 3917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Get the distribution options that are aliases for build_py 4017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # options -- list of packages and list of modules. 4117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.packages = self.distribution.packages 426f980b59368c022fe7c1925e83f909dabf74e634Greg Ward self.py_modules = self.distribution.py_modules 4317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.package_dir = self.distribution.package_dir 4413ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 4513ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 4613ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward def run (self): 4713ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 489b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # XXX copy_file by default preserves atime and mtime. IMHO this is 499b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # the right thing to do, but perhaps it should be an option -- in 509b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # particular, a site administrator might want installed files to 519b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # reflect the time of installation rather than the last 529b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # modification time before the installed release. 539b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward 549b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # XXX copy_file by default preserves mode, which appears to be the 559b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # wrong thing to do: if a file is read-only in the working 569b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # directory, we want it to be installed read/write so that the next 579b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # installation of the same module distribution can overwrite it 589b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # without problems. (This might be a Unix-specific issue.) Thus 599b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # we turn off 'preserve_mode' when copying to the build directory, 609b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # since the build directory is supposed to be exactly what the 619b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # installation will look like (ie. we preserve mode when 629b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # installing). 6313ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 6417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Two options control which modules will be installed: 'packages' 656f980b59368c022fe7c1925e83f909dabf74e634Greg Ward # and 'py_modules'. The former lets us work with whole packages, not 6617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # specifying individual modules at all; the latter is for 6717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # specifying modules one-at-a-time. Currently they are mutually 6817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # exclusive: you can define one or the other (or neither), but not 6917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # both. It remains to be seen how limiting this is. 7013ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 7117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Dispose of the two "unusual" cases first: no pure Python modules 7217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # at all (no problem, just return silently), and over-specified 736f980b59368c022fe7c1925e83f909dabf74e634Greg Ward # 'packages' and 'py_modules' options. 7417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 756f980b59368c022fe7c1925e83f909dabf74e634Greg Ward if not self.py_modules and not self.packages: 765d60fcf02a7050a07067a12c7a98c8b6b1e68372Greg Ward return 776f980b59368c022fe7c1925e83f909dabf74e634Greg Ward if self.py_modules and self.packages: 7817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward raise DistutilsOptionError, \ 796f980b59368c022fe7c1925e83f909dabf74e634Greg Ward "build_py: supplying both 'packages' and 'py_modules' " + \ 809b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward "options is not allowed" 8117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 826f980b59368c022fe7c1925e83f909dabf74e634Greg Ward # Now we're down to two cases: 'py_modules' only and 'packages' only. 836f980b59368c022fe7c1925e83f909dabf74e634Greg Ward if self.py_modules: 8417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.build_modules () 8517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 8617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.build_packages () 8717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 8817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # run () 895d60fcf02a7050a07067a12c7a98c8b6b1e68372Greg Ward 9017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 9117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def get_package_dir (self, package): 9217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward """Return the directory, relative to the top of the source 9317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward distribution, where package 'package' should be found 9417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward (at least according to the 'package_dir' option, if any).""" 9517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 96c0fe82ca26b1da22e35f2d0676f09795d052e4f0Greg Ward path = string.split (package, '.') 9717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 9817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not self.package_dir: 99631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward if path: 100631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward return apply (os.path.join, path) 101631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward else: 102631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward return '' 10317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 10417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward tail = [] 10517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward while path: 10617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward try: 10717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward pdir = self.package_dir[string.join (path, '.')] 10817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward except KeyError: 10917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward tail.insert (0, path[-1]) 11017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward del path[-1] 11117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 11217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward tail.insert (0, pdir) 11317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward return apply (os.path.join, tail) 11413ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward else: 1158bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # Oops, got all the way through 'path' without finding a 1168bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # match in package_dir. If package_dir defines a directory 1178bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # for the root (nameless) package, then fallback on it; 1188bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # otherwise, we might as well have not consulted 1198bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # package_dir at all, as we just use the directory implied 1208bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # by 'tail' (which should be the same as the original value 1218bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # of 'path' at this point). 1228bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward pdir = self.package_dir.get('') 1238bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward if pdir is not None: 1248bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward tail.insert(0, pdir) 1258bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward 126631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward if tail: 127631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward return apply (os.path.join, tail) 128631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward else: 129631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward return '' 13017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 13117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # get_package_dir () 13217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 13317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 13417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def check_package (self, package, package_dir): 13517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 13617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Empty dir name means current directory, which we can probably 13717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # assume exists. Also, os.path.exists and isdir don't know about 13817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # my "empty string means current dir" convention, so we have to 13917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # circumvent them. 14017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if package_dir != "": 14117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not os.path.exists (package_dir): 14217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward raise DistutilsFileError, \ 14317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward "package directory '%s' does not exist" % package_dir 14417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not os.path.isdir (package_dir): 14556359f591b361f41f661a14e5ed129bf8f22fa87Greg Ward raise DistutilsFileError, \ 14617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward ("supposed package directory '%s' exists, " + 14717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward "but is not a directory") % package_dir 14817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 14917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Require __init__.py for all but the "root package" 150631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward if package: 15117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward init_py = os.path.join (package_dir, "__init__.py") 1528bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward if os.path.isfile (init_py): 1538bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward return init_py 1548bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward else: 15517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.warn (("package init file '%s' not found " + 15617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward "(or not a regular file)") % init_py) 1578bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward 1588bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # Either not in a package at all (__init__.py not expected), or 1598bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # __init__.py doesn't exist -- so don't return the filename. 1608bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward return 1618bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward 16217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # check_package () 16317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 16417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 16517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def check_module (self, module, module_file): 16617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not os.path.isfile (module_file): 167113e70efa2b932a3ad2662875114133a1edb600cGreg Ward self.warn ("file %s (for module %s) not found" % 168113e70efa2b932a3ad2662875114133a1edb600cGreg Ward (module_file, module)) 16917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward return 0 17017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 17117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward return 1 17217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 17317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # check_module () 17417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 17517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 1762a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward def find_package_modules (self, package, package_dir): 1778b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward self.check_package (package, package_dir) 17817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward module_files = glob (os.path.join (package_dir, "*.py")) 1798b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward modules = [] 1809b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward setup_script = os.path.abspath (sys.argv[0]) 1819b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward 18217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward for f in module_files: 1839b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward abs_f = os.path.abspath (f) 1849b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward if abs_f != setup_script: 1859b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward module = os.path.splitext (os.path.basename (f))[0] 1868b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward modules.append ((package, module, f)) 1878b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return modules 18817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 18917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 1902a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward def find_modules (self): 1918bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward """Finds individually-specified Python modules, ie. those listed by 1926f980b59368c022fe7c1925e83f909dabf74e634Greg Ward module name in 'self.py_modules'. Returns a list of tuples (package, 1938bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward module_base, filename): 'package' is a tuple of the path through 1948bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward package-space to the module; 'module_base' is the bare (no 1958bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward packages, no dots) module name, and 'filename' is the path to the 1968bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward ".py" file (relative to the distribution root) that implements the 1978bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward module. 1988bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward """ 1998bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward 20017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Map package names to tuples of useful info about the package: 20117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # (package_dir, checked) 20217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # package_dir - the directory where we'll find source files for 20317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # this package 20417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # checked - true if we have checked that the package directory 20517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # is valid (exists, contains __init__.py, ... ?) 20617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward packages = {} 20717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 2088bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward # List of (package, module, filename) tuples to return 2092a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = [] 2102a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 21117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # We treat modules-in-packages almost the same as toplevel modules, 21217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # just the "package" for a toplevel is empty (either an empty 21317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # string or empty list, depending on context). Differences: 21417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # - don't check for __init__.py in directory for empty package 21517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 2166f980b59368c022fe7c1925e83f909dabf74e634Greg Ward for module in self.py_modules: 21717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward path = string.split (module, '.') 218c0fe82ca26b1da22e35f2d0676f09795d052e4f0Greg Ward package = string.join(path[0:-1], '.') 2192a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward module_base = path[-1] 22017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 22117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward try: 22217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward (package_dir, checked) = packages[package] 22317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward except KeyError: 22417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward package_dir = self.get_package_dir (package) 22517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward checked = 0 22617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 22717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not checked: 2288bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward init_py = self.check_package (package, package_dir) 22917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward packages[package] = (package_dir, 1) 2308bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward if init_py: 2318bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward modules.append((package, "__init__", init_py)) 23217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 23317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # XXX perhaps we should also check for just .pyc files 23417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # (so greedy closed-source bastards can distribute Python 23517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # modules too) 2362a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward module_file = os.path.join (package_dir, module_base + ".py") 23717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not self.check_module (module, module_file): 23817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward continue 23917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 2408bbba17d3815a44eefbd0cf33db937a56fe50db5Greg Ward modules.append ((package, module_base, module_file)) 2412a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2422a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward return modules 2432a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2442a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # find_modules () 2452a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2462a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2478b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def find_all_modules (self): 2488b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward """Compute the list of all modules that will be built, whether 2496f980b59368c022fe7c1925e83f909dabf74e634Greg Ward they are specified one-module-at-a-time ('self.py_modules') or 2508b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward by whole packages ('self.packages'). Return a list of tuples 2518b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward (package, module, module_file), just like 'find_modules()' and 2528b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 'find_package_modules()' do.""" 2532a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2546f980b59368c022fe7c1925e83f909dabf74e634Greg Ward if self.py_modules: 2552a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = self.find_modules () 2562a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward else: 2572a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = [] 2582a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward for package in self.packages: 2592a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward package_dir = self.get_package_dir (package) 2602a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward m = self.find_package_modules (package, package_dir) 2612a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules.extend (m) 2622a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2638b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return modules 2648b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2658b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # find_all_modules () 2668b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2678b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2688b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def get_source_files (self): 2698b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2708b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward modules = self.find_all_modules () 2712a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward filenames = [] 2722a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward for module in modules: 2732a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward filenames.append (module[-1]) 2742a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2758b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return filenames 2762a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2772a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2788b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def get_module_outfile (self, build_dir, package, module): 2798b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward outfile_path = [build_dir] + list(package) + [module + ".py"] 2808b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return apply (os.path.join, outfile_path) 2818b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2828b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2838b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def get_outputs (self): 2848b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward modules = self.find_all_modules () 2858b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward outputs = [] 2868b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward for (package, module, module_file) in modules: 2878b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward package = string.split (package, '.') 2888b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward outputs.append (self.get_module_outfile (self.build_lib, 2898b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward package, module)) 2908b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return outputs 2912a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2928b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2938b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def build_module (self, module, module_file, package): 2942a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward if type (package) is StringType: 2952a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward package = string.split (package, '.') 296631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward elif type (package) not in (ListType, TupleType): 297631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward raise TypeError, \ 298631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward "'package' must be a string (dot-separated), list, or tuple" 2992a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 3002a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # Now put the module source file into the "build" area -- this is 301e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # easy, we just copy it somewhere under self.build_lib (the build 3022a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # directory for Python source). 3038b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward outfile = self.get_module_outfile (self.build_lib, package, module) 3042a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward dir = os.path.dirname (outfile) 3052a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward self.mkpath (dir) 3069b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward self.copy_file (module_file, outfile, preserve_mode=0) 3072a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 3082a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 3092a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward def build_modules (self): 3102a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 3112a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = self.find_modules() 3128b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward for (package, module, module_file) in modules: 3132a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 31417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Now "build" the module -- ie. copy the source file to 315e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # self.build_lib (the build directory for Python source). 3162a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # (Actually, it gets copied to the directory for this package 317e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # under self.build_lib.) 31817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.build_module (module, module_file, package) 31917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 32017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # build_modules () 32117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 32217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 32317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def build_packages (self): 32417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 32517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward for package in self.packages: 3268b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 3278b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # Get list of (package, module, module_file) tuples based on 3288b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # scanning the package directory. 'package' is only included 3298b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # in the tuple so that 'find_modules()' and 3308b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # 'find_package_tuples()' have a consistent interface; it's 3318b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # ignored here (apart from a sanity check). Also, 'module' is 3328b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # the *unqualified* module name (ie. no dots, no package -- we 3338b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # already know its package!), and 'module_file' is the path to 3348b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # the .py file, relative to the current directory 3358b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # (ie. including 'package_dir'). 33617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward package_dir = self.get_package_dir (package) 3372a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = self.find_package_modules (package, package_dir) 33817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 33917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Now loop over the modules we found, "building" each one (just 340e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # copy it to self.build_lib). 3418b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward for (package_, module, module_file) in modules: 3428b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward assert package == package_ 34317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.build_module (module, module_file, package) 34417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 34517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # build_packages () 34613ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 347fcd974efbb71ab7cb5a75639028508e0195939b8Greg Ward# class build_py 348