[Zope-CVS] SVN: zpkgtools/trunk/zpkg - remove the Dependencies/Includes/ directory from distributions

Fred L. Drake, Jr. fdrake at gmail.com
Wed Aug 10 14:30:46 EDT 2005


Log message for revision 37846:
  - remove the Dependencies/Includes/ directory from distributions
  
  - remember what Python package provided a header, so we can build it
    out / install it in the right location
  
  - add a "build_headers" command that runs before "build_ext"; this
    makes the headers available in something more like the recommended
    structure, and runs as part of distutils.code.setup(), avoiding
    dependency on distribution construction artifacts
  
  - extend the "build" and "build_ext" commands so "build_headers" is
    run as needed
  
  - fix base directory computation for configuration loading in the case
    when no directory component is passed in
  

Changed:
  A   zpkgtools/trunk/zpkgsetup/build.py
  A   zpkgtools/trunk/zpkgsetup/build_ext.py
  A   zpkgtools/trunk/zpkgsetup/build_headers.py
  U   zpkgtools/trunk/zpkgsetup/dist.py
  U   zpkgtools/trunk/zpkgsetup/package.py
  U   zpkgtools/trunk/zpkgsetup/setup.py
  U   zpkgtools/trunk/zpkgtools/app.py
  U   zpkgtools/trunk/zpkgtools/config.py

-=-
Added: zpkgtools/trunk/zpkgsetup/build.py
===================================================================
--- zpkgtools/trunk/zpkgsetup/build.py	2005-08-10 18:20:20 UTC (rev 37845)
+++ zpkgtools/trunk/zpkgsetup/build.py	2005-08-10 18:30:46 UTC (rev 37846)
@@ -0,0 +1,35 @@
+"""Extended 'build' command that adds support for build_headers.
+
+"""
+__docformat__ = "reStructuredText"
+
+import distutils.command.build
+import os.path
+import sys
+
+
+class build(distutils.command.build.build):
+
+    user_options = distutils.command.build.build.user_options + [
+        ('build-headers=', None,
+         "build directory for headers"),
+        ]
+
+    def has_headers(self):
+        return self.distribution.has_headers()
+
+    # add build_headers before build_ext:
+    sub_commands = list(distutils.command.build.build.sub_commands)
+    for i in range(len(sub_commands)):
+        if sub_commands[i][0] == "build_ext":
+            sub_commands.insert(i, ("build_headers", has_headers))
+
+    def initialize_options(self):
+        distutils.command.build.build.initialize_options(self)
+        self.build_headers = None
+
+    def finalize_options(self):
+        distutils.command.build.build.finalize_options(self)
+        if self.build_headers is None:
+            self.build_headers = os.path.join(self.build_base,
+                                              "include-" + sys.version[0:3])


Property changes on: zpkgtools/trunk/zpkgsetup/build.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native

Added: zpkgtools/trunk/zpkgsetup/build_ext.py
===================================================================
--- zpkgtools/trunk/zpkgsetup/build_ext.py	2005-08-10 18:20:20 UTC (rev 37845)
+++ zpkgtools/trunk/zpkgsetup/build_ext.py	2005-08-10 18:30:46 UTC (rev 37846)
@@ -0,0 +1,29 @@
+"""Extended build_ext command that adds support for 'built' headers.
+
+If there are any public headers for any of the packages included in
+this distribution, the build/include-X.Y/ directory is added to the
+include path of the extensions being built.  This also ensures that
+the build_headers command runs before the build_ext command.
+
+"""
+__docformat__ = "reStructuredText"
+
+import distutils.command.build_ext
+import os.path
+
+
+class build_ext(distutils.command.build_ext.build_ext):
+
+    def run(self):
+        cmd = self.get_finalized_command("build_headers")
+        if cmd.package_headers:
+            self.run_command("build_headers")
+            self._extra_includes = cmd.build_dir
+        else:
+            self._extra_includes = None
+        distutils.command.build_ext.build_ext.run(self)
+
+    def build_extension(self, ext):
+        if self._extra_includes:
+            ext.include_dirs.append(self._extra_includes)
+        distutils.command.build_ext.build_ext.build_extension(self, ext)


Property changes on: zpkgtools/trunk/zpkgsetup/build_ext.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native

Added: zpkgtools/trunk/zpkgsetup/build_headers.py
===================================================================
--- zpkgtools/trunk/zpkgsetup/build_headers.py	2005-08-10 18:20:20 UTC (rev 37845)
+++ zpkgtools/trunk/zpkgsetup/build_headers.py	2005-08-10 18:30:46 UTC (rev 37846)
@@ -0,0 +1,53 @@
+"""
+"""
+__docformat__ = "reStructuredText"
+
+import distutils.core
+import distutils.util
+import os.path
+
+
+class build_headers(distutils.core.Command):
+    """Command that builds out the headers into build/headers-X.Y/.
+
+    The structure of the build/headers-X.Y/ directory is analogous to
+    that of the $exec_prefix/include/pythonX.Y/ directory: each
+    package gets a corresponding directory to which its public headers
+    are copied.  When the extension modules are built, this directory
+    will be added to the include search path before that containing
+    the Python headers.
+
+    """
+
+    description = "build out the public headers"
+
+    user_options = [
+        ('build-dir=', 'd', "directory to \"build\" (copy) to"),
+        ('force', 'f', "forcibly build everything (ignore file timestamps"),
+        ]
+
+    boolean_options = ['force']
+
+    def initialize_options (self):
+        self.build_dir = None
+        self.force = None
+        self.package_headers = None
+        self.outfiles = []
+
+    def finalize_options (self):
+        self.set_undefined_options('build',
+                                   ('build_headers', 'build_dir'),
+                                   ('force', 'force'))
+        self.package_headers = self.distribution.package_headers
+
+    def run(self):
+        if not self.package_headers:
+            return
+        for header in self.package_headers:
+            dir = os.path.join(self.build_dir, header.package)
+            self.mkpath(dir)
+            srcfile = distutils.util.convert_path(header.path)
+            outfile = os.path.join(
+                self.build_dir, header.package, os.path.basename(srcfile))
+            self.copy_file(srcfile, outfile)
+            self.outfiles.append(outfile)


Property changes on: zpkgtools/trunk/zpkgsetup/build_headers.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native

Modified: zpkgtools/trunk/zpkgsetup/dist.py
===================================================================
--- zpkgtools/trunk/zpkgsetup/dist.py	2005-08-10 18:20:20 UTC (rev 37845)
+++ zpkgtools/trunk/zpkgsetup/dist.py	2005-08-10 18:30:46 UTC (rev 37846)
@@ -19,7 +19,11 @@
 import distutils.extension
 import sys
 
+import zpkgsetup.build
+import zpkgsetup.build_ext
+import zpkgsetup.build_headers
 
+
 class ZPkgExtension(distutils.extension.Extension):
     """Distutils representation of a compiled extension module."""
 
@@ -29,9 +33,16 @@
 
     def __init__ (self, attrs=None):
         self.package_data = None
+        self.package_headers = attrs.pop("package_headers", ())
         distutils.dist.Distribution.__init__(self, attrs)
         if self.package_data and sys.version_info < (2, 4):
             from zpkgsetup.build_py import build_py
             from zpkgsetup.install_lib import install_lib
             self.cmdclass.setdefault('build_py', build_py)
             self.cmdclass.setdefault('install_lib', install_lib)
+        self.cmdclass.setdefault('build',
+                                 zpkgsetup.build.build)
+        self.cmdclass.setdefault('build_ext',
+                                 zpkgsetup.build_ext.build_ext)
+        self.cmdclass.setdefault('build_headers',
+                                 zpkgsetup.build_headers.build_headers)

Modified: zpkgtools/trunk/zpkgsetup/package.py
===================================================================
--- zpkgtools/trunk/zpkgsetup/package.py	2005-08-10 18:20:20 UTC (rev 37845)
+++ zpkgtools/trunk/zpkgsetup/package.py	2005-08-10 18:30:46 UTC (rev 37846)
@@ -75,6 +75,17 @@
 PACKAGE_CONF = "SETUP.cfg"
 
 
+class Header(object):
+    """Information about a header file and the package that provides it."""
+
+    def __init__(self, package, path):
+        self.package = package
+        self.path = path
+
+    def __repr__(self):
+        return "<Header(%r, %r)>" % (self.package, self.path)
+
+
 def loadPackageInfo(pkgname, directory, reldir):
     """Load package information for a Python package.
 
@@ -93,6 +104,8 @@
     pkginfo = read_package_info(directory, reldir)
     pkginfo.extensions = [create_extension(ext, pkgname, reldir)
                           for ext in pkginfo.extension]
+    pkginfo.package_headers = [Header(pkgname, path)
+                               for path in pkginfo.header]
     return pkginfo
 
 
@@ -112,6 +125,8 @@
     if pkginfo.extension:
         raise ValueError("extensions cannot be defined in collections")
     pkginfo.extensions = []
+    pkginfo.package_headers = [Header(pkgname, path)
+                               for path in pkginfo.header]
     return pkginfo
 
 

Modified: zpkgtools/trunk/zpkgsetup/setup.py
===================================================================
--- zpkgtools/trunk/zpkgsetup/setup.py	2005-08-10 18:20:20 UTC (rev 37845)
+++ zpkgtools/trunk/zpkgsetup/setup.py	2005-08-10 18:30:46 UTC (rev 37846)
@@ -66,6 +66,7 @@
         self.packages = []
         self.package_data = {}
         self.package_dir = {}
+        self.package_headers = []
         self.ext_modules = []
         self.scripts = []
         self.platforms = None
@@ -85,7 +86,7 @@
             depnames = os.listdir(depsdir)
             suffix = "-%s-%s" % (self._pkgname, self.version)
             for name in depnames:
-                if name != "Includes" and not name.endswith(suffix):
+                if not name.endswith(suffix):
                     # an unexpected name; we didn't put this here!
                     print >>sys.stderr, \
                           "unexpected name in Dependencies/: %r" % name
@@ -100,10 +101,6 @@
                 pkgdir = os.path.join(depdir, depname)
                 reldir = posixpath.join("Dependencies", name, depname)
                 self.scan(depname, pkgdir, reldir)
-            includes_dir = os.path.join(depsdir, "Includes")
-            if os.path.isdir(includes_dir):
-                for ext in self.ext_modules:
-                    ext.include_dirs.append(includes_dir)
 
     def setup(self):
         kwargs = self.__dict__.copy()
@@ -223,6 +220,7 @@
                 self.add_package_file(pkgname, posixpath.join(reldir, fn))
 
     def scan_basic(self, pkginfo):
+        self.package_headers.extend(pkginfo.package_headers)
         self.scripts.extend(pkginfo.script)
         if pkginfo.data_files:
             if self.data_files:

Modified: zpkgtools/trunk/zpkgtools/app.py
===================================================================
--- zpkgtools/trunk/zpkgtools/app.py	2005-08-10 18:20:20 UTC (rev 37845)
+++ zpkgtools/trunk/zpkgtools/app.py	2005-08-10 18:30:46 UTC (rev 37846)
@@ -173,7 +173,6 @@
                 component.write_setup_py(pathparts=["..", ".."],
                                          distclass=distclass)
                 component.write_setup_cfg()
-                self.add_headers(component)
         if self.options.application:
             top.write_setup_py(filename="install.py",
                                version=self.options.version,
@@ -190,22 +189,6 @@
         except zpkgtools.Error, e:
             self.error(str(e), rc=1)
 
-    def add_headers(self, component):
-        pkginfo = component.get_package_info()
-        if not pkginfo.header:
-            return
-        includes_dir = os.path.join(self.destination,
-                                    "Dependencies", "Includes")
-        if not os.path.isdir(includes_dir):
-            os.mkdir(includes_dir)
-        for src in pkginfo.header:
-            src = os.path.join(component.destination, *src.split("/"))
-            name = os.path.basename(src)
-            path = os.path.join(includes_dir, name)
-            if os.path.exists(path):
-                self.error("multiple headers with name %r" % name)
-            self.ip.copy_file(src, path)
-
     def add_manifest(self, destination):
         self.ip.add_manifest(destination)
         self.ip.add_output(os.path.join(destination, "MANIFEST"))

Modified: zpkgtools/trunk/zpkgtools/config.py
===================================================================
--- zpkgtools/trunk/zpkgtools/config.py	2005-08-10 18:20:20 UTC (rev 37845)
+++ zpkgtools/trunk/zpkgtools/config.py	2005-08-10 18:30:46 UTC (rev 37846)
@@ -140,9 +140,14 @@
             paths found in the configuration file.
 
         """
-        p = cfgparser.Parser(f, path, Schema(path, self.locations))
+        if basedir:
+            basedir = os.path.abspath(basedir)
+        else:
+            basedir = os.getcwd()
+        p = cfgparser.Parser(f, path, Schema(os.path.abspath(path),
+                                             self.locations))
         cf = p.load()
-        base = urlutils.file_url(os.path.abspath(basedir)) + "/"
+        base = urlutils.file_url(basedir) + "/"
         for value in cf.resource_map:
             value = urlparse.urljoin(base, value)
             self.location_maps.append(value)



More information about the Zope-CVS mailing list