commands.py :  » Development » PyObjC » trunk » pyobjc » pyobjc-metadata » Lib » PyObjCMetaData » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » PyObjC 
PyObjC » trunk » pyobjc » pyobjc metadata » Lib » PyObjCMetaData » commands.py
"""
Some distutils commands that make it easier to work with the metadata in a
project:

* update_metadata 

  This command runs the metadata generator and refreshes the 
  PyObjC.bridgesupport file.

* update_exceptions

  This command runs the metadata generator and refreshes the metadata
  exceptions file.

* build_html

  Convert documentation in the 'Doc' directory from text to HTML using
  docutils. Requires docutils to be installed.

* bdist_mpkg

  A subclass of the generic bdist_mpkg command that will automaticly include
  documentation and examples as well (when these are present).

  (This one is not actually defined here, we just change the configuration
  of the standard bdist_mpkg command).

* update_static_inlines

  Update wrapper module for static inline functions

"""
__all__ = [ 'extra_cmdclass', 'extra_options' ]

from setuptools import Command
from distutils.dep_util import newer
from distutils.command.build import build
import subprocess
import os, sys
from PyObjCMetaData.et import *

# Additional schemes for bdist_mpkg
CUSTOM_SCHEMES=dict(
    docs=dict(
        description=u"(Optional) Documentation for the %(framework)s wrapper",
        prefix=u'/Developer/Documentation/Python/PyObjC/%(framework)s',
        source='Doc',
    ),
    examples=dict(
        description=u"(Optional) Examples for the %(framework)s wrapper",
        prefix=u'/Developer/Examples/Python/PyObjC/%(framework)s',
        source='Examples',
    )
)


#
# Implementation for update_metadata and update_exceptions
#


def _path_to_script(scriptname):
    """
    Return the full path of a python script. 

    Scripts are usually installed in ${sys.prefix}/bin, but Apple has tweaked
    the system python on Leopard to install in /usr/local/bin instead.
    """
    if sys.prefix.startswith('/System') and os.uname()[2] >= '9.':
        return os.path.join('/usr/local/bin', scriptname)
    return os.path.join(sys.prefix, 'bin', scriptname)


class BaseCommand (Command):
    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass


    def get_files(self):
        files = [ fn for fn in os.listdir('Exceptions') if fn.endswith('.bridgesupport') ]
        if not files:
            raise RuntimeError, "Cannot find exception file"

        for fn in files:
            exceptionsfile = os.path.join('Exceptions', fn)
            framework = os.path.splitext(fn)[0]
            metadatafile = os.path.join('Lib', framework, 
                    'PyObjC.bridgesupport')
            if not os.path.exists(metadatafile):
                for subdir in os.listdir('Lib'):
                    metadatafile = os.path.join('Lib', subdir, framework,
                            'PyObjC.bridgesupport')
                    if os.path.exists(metadatafile):
                        break
                else:
                    metadatafile = os.path.join('Lib', framework, 
                        'PyObjC.bridgesupport')

            yield framework, exceptionsfile, metadatafile

class update_exceptions (BaseCommand):
    description = "Update the metadata exceptions file"

    def run(self):
        for framework, exceptionsfile, metadatafile in self.get_files():
            result = subprocess.call([
                _path_to_script('pyobjc-metadata-gen'), 
                '-v',
                '-f', framework,
                '-F', 'both',
                '-e', exceptionsfile,
                '-o', metadatafile,
                '-O', exceptionsfile,
                ])
            if result != 0:
                raise RuntimeError, "Updating metadata failed"

class update_metadata (BaseCommand):
    description = "Update the metadata file"

    def run(self):
        for framework, exceptionsfile, metadatafile in self.get_files():
            result = subprocess.call([
                _path_to_script('pyobjc-metadata-gen'), 
                '-v',
                '-f', framework,
                '-F', 'final-md',
                '-e', exceptionsfile,
                '-o', metadatafile])
            if result != 0:
                raise RuntimeError, "Updating metadata failed"

#
# Implementation for the build_html command
# 

def rest2HTML(irrelevant, dirName, names):
    while '.svn' in names:
        names.remove('.svn')
    for aName in names:
        if aName.endswith('.txt'):
            anInputPath = os.path.join(dirName, aName)
            if irrelevant is not None and anInputPath in irrelevant:
                continue
            anOutputPath = anInputPath[:-4] + '.html'
            if not newer(anInputPath, anOutputPath):
                print '- %s (skipped: up to date)' % (anInputPath,)
                continue
            print '- %s'%(anInputPath)
            outfile = file(anOutputPath, 'w')
            ret = subprocess.call([TOOL, anInputPath], stdout=outfile)
            outfile.close()
            if ret:
                os.remove(anOutputPath)

def _iter_paths():
    try:
        import DocArticle
    except ImportError:
        return
    yield os.path.dirname(os.path.dirname(DocArticle.__file__))
    for path in os.environ.get('PATH', '/usr/bin:/usr/local/bin').split(':'):
        yield path

for path in _iter_paths():
    TOOL = os.path.join(path, 'docarticle.py')
    if os.path.exists(TOOL):
        break
else:
    TOOL = None

class build_html(Command):
    description = "Generate HTML from ReST documentation"
    user_options = []

    def initialize_options(self):
        self.finalized = False

    def finalize_options(self):
        self.finalized = True

    def run(self):
        if TOOL is None:
            print "*** Can't generate HTML, docutils is not installed"
            return

        os.path.walk('Doc', rest2HTML, [])


INLINES_HEADER="""\
#include "Python.h"
#import <%(framework)s/%(framework)s.h>

typedef void (*FUNCTION)(void);

struct function_map {
    const char* name;
    FUNCTION    function;
} function_map[] = {
"""

INLINES_FOOTER="""\
    { 0, 0 }
};

static PyMethodDef mod_methods[] = {
        { 0, 0, 0, 0 } /* sentinel */
};

void init_inlines(void)
{
    PyObject* m = Py_InitModule4("_inlines", mod_methods, NULL, NULL, PYTHON_API_VERSION);

    PyModule_AddObject(m, "_inline_list_", 
        PyCObject_FromVoidPtr(function_map, NULL));
}
"""

class update_static_inlines (BaseCommand):
    def run(self):
        for  framework, exceptionsfile, metadatafile in self.get_files():
            meta = ET.parse(metadatafile).getroot()
            inlines = [ e.get('name') for e in meta.findall('function') if e.get('inline', 'false') == 'true' ]
            fn = os.path.join('Modules', '_%s_inlines.m'%(framework,))
            if not inlines:
                if os.path.exists(fn):
                    print " *** %s exists, but no inlines left"%(fn,)

                else:
                    # No inlines.m present and no inlines: just go to the
                    # next metadata file.
                    continue

            else:
                if not os.path.exists(fn):
                    print " *** added %s, please add a new extension to setup.py"%(fn,)

            fp = open(fn, 'w')
            fp.write(INLINES_HEADER % locals())
            for nm in inlines:
                fp.write('\t{"%s", (FUNCTION)&%s },\n'%(nm, nm))
            fp.write(INLINES_FOOTER)


#
# Setup our public interface
#

def _mpkg_options(framework):
    """
    Generate additional options for bdist_mpkg.
    """

    custom_schemes = CUSTOM_SCHEMES.copy()
    if not os.path.exists('Doc'):
        del custom_schemes['docs']
    if not os.path.exists('Examples'):
        del custom_schemes['examples']

    for scheme in custom_schemes.values():
        for k in scheme.keys():
            scheme[k] = scheme[k] % locals()

    opts = dict(
        custom_schemes=custom_schemes,
        readme='README.txt',
        license='LICENSE.txt',
    )

    if 'docs' in custom_schemes:
        opts['scheme_command'] = dict(docs='build_html')

    if not os.path.exists('README.txt'):
        del opts['readme']

    if not os.path.exists('LICENSE.txt'):
        del opts['license']

    return opts


extra_cmdclass = {
    'update_static_inlines': update_static_inlines,
    'update_metadata': update_metadata, 
    'update_exceptions': update_exceptions,
}

if os.path.exists('Doc'):
    extra_cmdclass['build_html'] = build_html

def extra_options(framework):
    """
    Return a dictionary with additional distutils options.

    Usage:

    setup=(
        ...
        options=extra_options('AppKit'),
    )
    """
    return {
        'bdist_mpkg': _mpkg_options(framework),
    }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.