build_py.py revision 8b2e95edd69cacafdfbcf00270065bd6444f3336
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"), 23bbeceeaf9a5edf878154b17a6a94403a26822d51Greg Ward ] 2413ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 2513ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 26e01149cbe83778a5cf872a6b429ff33179b7cdcbGreg Ward def initialize_options (self): 27e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward self.build_lib = None 2871eb8644d7e27fd379a2cf78c509155bdb179332Greg Ward self.modules = None 2971eb8644d7e27fd379a2cf78c509155bdb179332Greg Ward self.package = None 3017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.package_dir = None 3113ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 32e01149cbe83778a5cf872a6b429ff33179b7cdcbGreg Ward def finalize_options (self): 3313ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward self.set_undefined_options ('build', 34e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward ('build_lib', 'build_lib')) 3517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 3617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Get the distribution options that are aliases for build_py 3717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # options -- list of packages and list of modules. 3817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.packages = self.distribution.packages 3917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.modules = self.distribution.py_modules 4017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.package_dir = self.distribution.package_dir 4113ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 4213ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 4313ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward def run (self): 4413ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 459b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # XXX copy_file by default preserves atime and mtime. IMHO this is 469b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # the right thing to do, but perhaps it should be an option -- in 479b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # particular, a site administrator might want installed files to 489b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # reflect the time of installation rather than the last 499b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # modification time before the installed release. 509b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward 519b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # XXX copy_file by default preserves mode, which appears to be the 529b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # wrong thing to do: if a file is read-only in the working 539b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # directory, we want it to be installed read/write so that the next 549b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # installation of the same module distribution can overwrite it 559b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # without problems. (This might be a Unix-specific issue.) Thus 569b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # we turn off 'preserve_mode' when copying to the build directory, 579b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # since the build directory is supposed to be exactly what the 589b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # installation will look like (ie. we preserve mode when 599b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward # installing). 6013ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 6117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Two options control which modules will be installed: 'packages' 6217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # and 'modules'. The former lets us work with whole packages, not 6317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # specifying individual modules at all; the latter is for 6417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # specifying modules one-at-a-time. Currently they are mutually 6517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # exclusive: you can define one or the other (or neither), but not 6617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # both. It remains to be seen how limiting this is. 6713ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 6817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Dispose of the two "unusual" cases first: no pure Python modules 6917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # at all (no problem, just return silently), and over-specified 7017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # 'packages' and 'modules' options. 7117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 7217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not self.modules and not self.packages: 735d60fcf02a7050a07067a12c7a98c8b6b1e68372Greg Ward return 7417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if self.modules and self.packages: 7517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward raise DistutilsOptionError, \ 7617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward "build_py: supplying both 'packages' and 'modules' " + \ 779b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward "options is not allowed" 7817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 7917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Now we're down to two cases: 'modules' only and 'packages' only. 8017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if self.modules: 8117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.build_modules () 8217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 8317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.build_packages () 8417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 8517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # run () 865d60fcf02a7050a07067a12c7a98c8b6b1e68372Greg Ward 8717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 8817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def get_package_dir (self, package): 8917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward """Return the directory, relative to the top of the source 9017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward distribution, where package 'package' should be found 9117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward (at least according to the 'package_dir' option, if any).""" 9217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 9317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if type (package) is StringType: 9417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward path = string.split (package, '.') 9517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward elif type (package) in (TupleType, ListType): 96631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward path = list (package) 9717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 9817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward raise TypeError, "'package' must be a string, list, or tuple" 9917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 10017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not self.package_dir: 101631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward if path: 102631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward return apply (os.path.join, path) 103631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward else: 104631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward return '' 10517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 10617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward tail = [] 10717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward while path: 10817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward try: 10917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward pdir = self.package_dir[string.join (path, '.')] 11017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward except KeyError: 11117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward tail.insert (0, path[-1]) 11217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward del path[-1] 11317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 11417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward tail.insert (0, pdir) 11517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward return apply (os.path.join, tail) 11613ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward else: 11717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # arg! everything failed, we might as well have not even 11817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # looked in package_dir -- oh well 119631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward if tail: 120631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward return apply (os.path.join, tail) 121631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward else: 122631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward return '' 12317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 12417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # get_package_dir () 12517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 12617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 12717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def check_package (self, package, package_dir): 12817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 12917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Empty dir name means current directory, which we can probably 13017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # assume exists. Also, os.path.exists and isdir don't know about 13117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # my "empty string means current dir" convention, so we have to 13217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # circumvent them. 13317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if package_dir != "": 13417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not os.path.exists (package_dir): 13517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward raise DistutilsFileError, \ 13617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward "package directory '%s' does not exist" % package_dir 13717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not os.path.isdir (package_dir): 13856359f591b361f41f661a14e5ed129bf8f22fa87Greg Ward raise DistutilsFileError, \ 13917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward ("supposed package directory '%s' exists, " + 14017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward "but is not a directory") % package_dir 14117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 14217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Require __init__.py for all but the "root package" 143631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward if package: 14417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward init_py = os.path.join (package_dir, "__init__.py") 14517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not os.path.isfile (init_py): 14617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.warn (("package init file '%s' not found " + 14717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward "(or not a regular file)") % init_py) 14817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # check_package () 14917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 15017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 15117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def check_module (self, module, module_file): 15217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not os.path.isfile (module_file): 153113e70efa2b932a3ad2662875114133a1edb600cGreg Ward self.warn ("file %s (for module %s) not found" % 154113e70efa2b932a3ad2662875114133a1edb600cGreg Ward (module_file, module)) 15517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward return 0 15617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward else: 15717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward return 1 15817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 15917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # check_module () 16017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 16117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 1622a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward def find_package_modules (self, package, package_dir): 1638b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward self.check_package (package, package_dir) 16417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward module_files = glob (os.path.join (package_dir, "*.py")) 1658b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward modules = [] 1669b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward setup_script = os.path.abspath (sys.argv[0]) 1679b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward 16817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward for f in module_files: 1699b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward abs_f = os.path.abspath (f) 1709b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward if abs_f != setup_script: 1719b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward module = os.path.splitext (os.path.basename (f))[0] 1728b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward modules.append ((package, module, f)) 1738b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return modules 17417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 17517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 1762a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward def find_modules (self): 17717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Map package names to tuples of useful info about the package: 17817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # (package_dir, checked) 17917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # package_dir - the directory where we'll find source files for 18017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # this package 18117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # checked - true if we have checked that the package directory 18217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # is valid (exists, contains __init__.py, ... ?) 18317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward packages = {} 18417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 1852a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # List of (module, package, filename) tuples to return 1862a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = [] 1872a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 18817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # We treat modules-in-packages almost the same as toplevel modules, 18917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # just the "package" for a toplevel is empty (either an empty 19017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # string or empty list, depending on context). Differences: 19117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # - don't check for __init__.py in directory for empty package 19217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 19317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward for module in self.modules: 19417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward path = string.split (module, '.') 19517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward package = tuple (path[0:-1]) 1962a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward module_base = path[-1] 19717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 19817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward try: 19917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward (package_dir, checked) = packages[package] 20017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward except KeyError: 20117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward package_dir = self.get_package_dir (package) 20217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward checked = 0 20317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 20417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not checked: 20517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.check_package (package, package_dir) 20617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward packages[package] = (package_dir, 1) 20717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 20817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # XXX perhaps we should also check for just .pyc files 20917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # (so greedy closed-source bastards can distribute Python 21017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # modules too) 2112a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward module_file = os.path.join (package_dir, module_base + ".py") 21217dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward if not self.check_module (module, module_file): 21317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward continue 21417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 2158b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward modules.append ((package, module, module_file)) 2162a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2172a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward return modules 2182a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2192a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # find_modules () 2202a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2212a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2228b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def find_all_modules (self): 2238b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward """Compute the list of all modules that will be built, whether 2248b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward they are specified one-module-at-a-time ('self.modules') or 2258b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward by whole packages ('self.packages'). Return a list of tuples 2268b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward (package, module, module_file), just like 'find_modules()' and 2278b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 'find_package_modules()' do.""" 2282a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2292a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward if self.modules: 2302a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = self.find_modules () 2312a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward else: 2322a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = [] 2332a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward for package in self.packages: 2342a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward package_dir = self.get_package_dir (package) 2352a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward m = self.find_package_modules (package, package_dir) 2362a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules.extend (m) 2372a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2388b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return modules 2398b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2408b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # find_all_modules () 2418b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2428b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2438b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def get_source_files (self): 2448b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2458b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward modules = self.find_all_modules () 2462a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward filenames = [] 2472a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward for module in modules: 2482a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward filenames.append (module[-1]) 2492a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2508b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return filenames 2512a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2522a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2538b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def get_module_outfile (self, build_dir, package, module): 2548b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward outfile_path = [build_dir] + list(package) + [module + ".py"] 2558b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return apply (os.path.join, outfile_path) 2568b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2578b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2588b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def get_outputs (self): 2598b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward modules = self.find_all_modules () 2608b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward outputs = [] 2618b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward for (package, module, module_file) in modules: 2628b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward package = string.split (package, '.') 2638b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward outputs.append (self.get_module_outfile (self.build_lib, 2648b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward package, module)) 2658b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward return outputs 2662a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2678b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 2688b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward def build_module (self, module, module_file, package): 2692a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward if type (package) is StringType: 2702a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward package = string.split (package, '.') 271631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward elif type (package) not in (ListType, TupleType): 272631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward raise TypeError, \ 273631e6a0c070810b064c48ff6cf777ebb0276f038Greg Ward "'package' must be a string (dot-separated), list, or tuple" 2742a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2752a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # Now put the module source file into the "build" area -- this is 276e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # easy, we just copy it somewhere under self.build_lib (the build 2772a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # directory for Python source). 2788b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward outfile = self.get_module_outfile (self.build_lib, package, module) 2792a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward dir = os.path.dirname (outfile) 2802a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward self.mkpath (dir) 2819b45443c1bdf99b0f27b12baf06fea475b60e145Greg Ward self.copy_file (module_file, outfile, preserve_mode=0) 2822a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2832a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2842a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward def build_modules (self): 2852a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 2862a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = self.find_modules() 2878b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward for (package, module, module_file) in modules: 2882a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward 28917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Now "build" the module -- ie. copy the source file to 290e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # self.build_lib (the build directory for Python source). 2912a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward # (Actually, it gets copied to the directory for this package 292e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # under self.build_lib.) 29317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.build_module (module, module_file, package) 29417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 29517dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # build_modules () 29617dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 29717dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 29817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward def build_packages (self): 29917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 30017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward for package in self.packages: 3018b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward 3028b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # Get list of (package, module, module_file) tuples based on 3038b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # scanning the package directory. 'package' is only included 3048b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # in the tuple so that 'find_modules()' and 3058b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # 'find_package_tuples()' have a consistent interface; it's 3068b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # ignored here (apart from a sanity check). Also, 'module' is 3078b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # the *unqualified* module name (ie. no dots, no package -- we 3088b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # already know its package!), and 'module_file' is the path to 3098b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # the .py file, relative to the current directory 3108b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward # (ie. including 'package_dir'). 31117dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward package_dir = self.get_package_dir (package) 3122a612067e60a98f05d39b39f4a7a5a7a8065bfc9Greg Ward modules = self.find_package_modules (package, package_dir) 31317dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 31417dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # Now loop over the modules we found, "building" each one (just 315e6916516828a88ab71fab7a749f8c9cf6b52775aGreg Ward # copy it to self.build_lib). 3168b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward for (package_, module, module_file) in modules: 3178b2e95edd69cacafdfbcf00270065bd6444f3336Greg Ward assert package == package_ 31817dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward self.build_module (module, module_file, package) 31917dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward 32017dc6e7ed8cd62068b5f244a9f1023917d3caf4aGreg Ward # build_packages () 32113ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward 32213ae1c8ff81befcfd0b0ece98ef471cd504642d8Greg Ward# end class BuildPy 323