[Zodb-checkins] CVS: ZODB4 - setup.py:1.10

Jeremy Hylton jeremy@zope.com
Thu, 6 Mar 2003 14:48:41 -0500


Update of /cvs-repository/ZODB4
In directory cvs.zope.org:/tmp/cvs-serv2747

Modified Files:
	setup.py 
Log Message:
Use the Zope3 Finder to find extra files like .txt and .xml,
but continue to use an explicit package list.

Add winlock to the optional list.
Fix the .h file references.


=== ZODB4/setup.py 1.9 => 1.10 ===
--- ZODB4/setup.py:1.9	Tue Jan  7 18:32:23 2003
+++ ZODB4/setup.py	Thu Mar  6 14:48:39 2003
@@ -22,17 +22,25 @@
 ZODBv4 is compatible with Python 2.2 new-style classes.
 """
 
+import os
+import sys
+
+# Provide a bunch of custom components that make it possible to build and
+# install non-.py files into the package destinations.
+from distutils import dir_util
+from distutils.command.build import build as buildcmd
+from distutils.command.build_ext import build_ext
+from distutils.command.install_lib import install_lib as installcmd
 from distutils.core import setup
+from distutils.dist import Distribution
 from distutils.extension import Extension
 
-import glob
-import os
-import sys
 
-# A hack to determine if Extension objects support the depends keyword arg.
+# A hack to determine if Extension objects support the `depends' keyword arg,
+# which only exists in Python 2.3's distutils.
 if not "depends" in Extension.__init__.func_code.co_varnames:
-    # If it doesn't, create a local replacement that removes depends
-    # from the kwargs before calling the regular constructor.
+    # If it doesn't, create a local replacement that removes depends from the
+    # kwargs before calling the regular constructor.
     _Extension = Extension
     class Extension(_Extension):
         def __init__(self, name, sources, **kwargs):
@@ -40,60 +48,99 @@
                 del kwargs["depends"]
             _Extension.__init__(self, name, sources, **kwargs)
 
-def copy_conf_files(cmd, outputbase):
-    for relpath in [
-        os.path.join("ZConfig", "tests", "input"),
-        os.path.join("ZConfig", "tests", "library"),
-        os.path.join("ZConfig", "tests", "library", "thing"),
-        os.path.join("ZConfig", "tests", "library", "thing", "ext"),
-        os.path.join("ZConfig", "tests", "library", "widget"),
-        ]:
-        inputdir = os.path.join("src", relpath)
-        outputdir = os.path.join(outputbase, relpath)
-        if not os.path.exists(outputdir):
-            dir_util.mkpath(outputdir)
-        for fn in os.listdir(inputdir):
-            base, ext = os.path.splitext(fn)
-            if ext not in (".conf", ".txt", ".xml"):
-                continue
-            cmd.copy_file(os.path.join(inputdir, fn),
-                          os.path.join(outputdir, fn))
 
-# provide a bunch of customer components that make it possible
-# to install a non .py file into one of the packages
-from distutils import dir_util
-from distutils.core import setup
-from distutils.dist import Distribution
-from distutils.command.install_lib import install_lib
-from distutils.command.build_py import build_py
-
-class MyLibInstaller(install_lib):
-    """Custom library installer, used to put hosttab in the right place."""
-    # We use the install_lib command since we need to put hosttab
-    # inside the library directory.  This is where we already have the
-    # real information about where to install it after the library
-    # location has been set by any relevant distutils command line
-    # options.
+# We have to snoop for file types that distutils doesn't copy correctly when
+# doing a non-build-in-place.
+EXTS = ['.conf', '.dtd', '.txt', '.xml']
+
+# This class serves multiple purposes.  It walks the file system looking for
+# auxiliary files that distutils doesn't install properly, and it actually
+# copies those files (when hooked into by distutils).  It also walks the file
+# system looking for candidate packages for distutils to install as normal.
+# The key here is that the package must have an __init__.py file.
+class Finder:
+    def __init__(self, exts, prefix):
+        self._files = []
+        self._pkgs = {}
+        self._exts = exts
+        # We're finding packages in lib/python in the source dir, but we're
+        # copying them directly under build/lib.<plat>.  So we need to lop off
+        # the prefix when calculating the package names from the file names.
+        self._plen = len(prefix)
+
+    def visit(self, ignore, dir, files):
+        for file in files:
+            # First see if this is one of the packages we want to add, or if
+            # we're really skipping this package.
+            if '__init__.py' in files:
+                aspkg = dir[self._plen:].replace(os.sep, '.')
+                self._pkgs[aspkg] = True
+            # Add any extra files we're interested in
+            base, ext = os.path.splitext(file)
+            if ext in self._exts:
+                self._files.append(os.path.join(dir, file))
+
+    def copy_files(self, cmd, outputbase):
+        for file in self._files:
+            dest = os.path.join(outputbase, file[self._plen:])
+            # Make sure the destination directory exists
+            dir = os.path.dirname(dest)
+            if not os.path.exists(dir):
+                dir_util.mkpath(dir)
+            cmd.copy_file(file, dest)
+
+    def get_packages(self):
+        return self._pkgs.keys()
+
+def remove_stale_bytecode(arg, dirname, names):
+    names = map(os.path.normcase, names)
+    for name in names:
+        if name.endswith(".pyc") or name.endswith(".pyo"):
+            srcname = name[:-1]
+            if srcname not in names:
+                fullname = os.path.join(dirname, name)
+                print "Removing stale bytecode file", fullname
+                os.unlink(fullname)
+
+# Create the finder instance, which will be used in lots of places.  `finder'
+# is the global we're most interested in.
+basedir = 'src/'
+finder = Finder(EXTS, basedir)
+os.path.walk(basedir, finder.visit, None)
 
+# Distutils hook classes
+class MyBuilder(buildcmd):
     def run(self):
-        install_lib.run(self)
-        copy_conf_files(self, self.install_dir)
+        os.path.walk(os.curdir, remove_stale_bytecode, None)
+        buildcmd.run(self)
+        finder.copy_files(self, self.build_lib)
+
+class MyExtBuilder(build_ext):
+    # Override the default build_ext to remove stale bytecodes.
+    # Technically, removing bytecode has nothing to do with
+    # building extensions, but Zope's the build_ext -i variant
+    # is used to build Zope in place.
+    def run(self):
+        os.path.walk(os.curdir, remove_stale_bytecode, None)
+        build_ext.run(self)
 
-class MyPyBuilder(build_py):
-    def build_packages(self):
-        build_py.build_packages(self)
-        copy_conf_files(self, self.build_lib)
+class MyLibInstaller(installcmd):
+    def run(self):
+        installcmd.run(self)
+        extra.copy_files(self, self.install_dir)
 
 class MyDistribution(Distribution):
     # To control the selection of MyLibInstaller and MyPyBuilder, we
     # have to set it into the cmdclass instance variable, set in
     # Distribution.__init__().
-
     def __init__(self, *attrs):
         Distribution.__init__(self, *attrs)
-        self.cmdclass['build_py'] = MyPyBuilder
+        self.cmdclass['build'] = MyBuilder
+        self.cmdclass['build_ext'] = MyExtBuilder
         self.cmdclass['install_lib'] = MyLibInstaller
 
+
+# Set up dependencies for the BTrees package
 base_btrees_depends = [
     "src/persistence/persistence.h",
     "src/persistence/persistenceAPI.h",
@@ -143,6 +190,12 @@
     Extension("zodb.storage._helper", ["src/zodb/storage/_helper.c"]),
     ]
 
+# On Window, there are more extensions that need to be built
+if sys.platform == "win32":
+    ext_modules += [Extension("zodb.winlock", ["src/zodb/winlock.c"])]
+
+# While the Finder can explicitly list all the packages, ZODB4 is
+# small enough that it is seems better to list the packages explicitly.
 packages = [
     "zodb", "zodb.btrees", "zodb.code", "zodb.storage",
     "zodb.zeo", "zodb.zeo.zrpc",
@@ -154,16 +207,17 @@
     "zdaemon",
     ]
 
-if sys.version_info < (2, 3):
+if sys.version_info < (2, 3) or "sdist" in sys.argv:
     # the logging package becomes a std feature in 2.3
     packages.append("logging")
 
 def hastests(p):
     path = "src/%s/tests" % "/".join(p.split("."))
     return os.path.isdir(path)
-
+  
 packages += ["%s.tests" % p for p in packages if hastests(p)]
 
+# We're using the module docstring as the distutils descriptions.
 doclines = __doc__.split("\n")
 
 setup(name="ZODB4",
@@ -174,7 +228,9 @@
       packages = packages,
       package_dir = {'': 'src'},
       ext_modules = ext_modules,
-      headers = ["ZODB/cPersistence.h", "ZODB/cPersistenceAPI.h"],
+      headers = ["src/persistence/persistence.h",
+                 "src/persistence/persistenceAPI.h",
+                 ],
       license = "http://www.zope.org/Resources/ZPL",
       platforms = ["any"],
       description = doclines[0],