buildframework/helium/sf/python/pythoncore/lib/sphinx_ext.py
author lorewang
Wed, 01 Dec 2010 16:05:36 +0800
changeset 715 e0739b8406dd
parent 645 b8d81fa19e7d
permissions -rw-r--r--
Specify extenal tool with path
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
     1
#============================================================================ 
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
     2
#Name        : sphinx_ext.py 
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
     3
#Part of     : Helium 
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
     4
#
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
     5
#Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
     6
#All rights reserved.
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
     7
#This component and the accompanying materials are made available
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
     8
#under the terms of the License "Eclipse Public License v1.0"
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
     9
#which accompanies this distribution, and is available
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    10
#at the URL "http://www.eclipse.org/legal/epl-v10.html".
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    11
#
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    12
#Initial Contributors:
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    13
#Nokia Corporation - initial contribution.
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    14
#
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    15
#Contributors:
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    16
#
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    17
#Description:
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    18
#===============================================================================
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    19
""" Custom Sphinx operations to help with Helium doc linking. """
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    20
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    21
import os
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    22
import re
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    23
import atexit
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    24
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    25
from docutils import nodes, utils
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    26
from docutils.parsers.rst import directives
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    27
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    28
import amara
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    29
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    30
tree = None
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    31
treecache = None
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    32
database_path = os.path.abspath(os.path.join(os.getcwd() + '/build', 'public_database.xml'))
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    33
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    34
# Error count for custom sphinx operations
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    35
exit_with_failure = 0 
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    36
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    37
def check_cached_database():
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    38
    """ Check the Ant database XML data is cached as needed. """
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    39
    global tree
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    40
    global treecache    
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    41
    
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    42
    if tree == None or treecache == None:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    43
        f = open(database_path)
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    44
        tree = amara.parse(f)
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    45
    
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    46
        treecache = {}
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    47
        for project in tree.antDatabase.project:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    48
            for x in project.xml_children:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    49
                if hasattr(x, 'name'):
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    50
                    treecache[str(x.name)] = [str(project.name),'project']
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    51
        if hasattr(tree.antDatabase, "antlib"):
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    52
            for antlib in tree.antDatabase.antlib:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    53
                for x in antlib.xml_children:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    54
                    if hasattr(x, 'name'):
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    55
                        treecache[str(x.name)] = [str(antlib.name),'antlib']
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    56
        
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    57
def handle_hlm_role(role, _, text, lineno, inliner, options=None, content=None): # pylint: disable=W0613
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    58
    """ Process a custom Helium ReStructuredText role to link to a target, property or macro. """
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    59
    if options == None:
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    60
        options = {}
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    61
    if content == None:
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
    62
        content = []
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    63
        
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    64
    # See if the role is used to embed a API element field
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    65
    if '[' in text:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    66
        role_data = _embed_role_field(role, text, lineno, inliner)
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    67
    else:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    68
        role_data = _build_link(text, lineno, inliner, options)
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    69
        
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    70
    return role_data
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    71
    
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    72
def _embed_role_field(role, text, lineno, inliner):
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    73
    """ Insert the contents of an element field. 
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    74
    
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    75
    These take the form of e.g. hlm-p:`build.drive[summary]`
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    76
    """
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    77
    messages = []
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    78
    node = nodes.Text('', '')
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    79
    
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    80
    field_match = re.search("(.*?)\[(.*?)\]", text)
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    81
    if field_match != None:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    82
        element_name = field_match.group(1)
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    83
        field_name = field_match.group(2)
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    84
        if field_name != None and len(field_name) > 0:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    85
            field_value = find_field_value(role, element_name, field_name)
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    86
            if field_value != None and len(field_value) > 0:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    87
                node = nodes.Text(field_value, utils.unescape(field_value))
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    88
            else:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    89
                messages.append(inliner.reporter.error(('Field value cannot be found for API field: "%s".' % text), line=lineno))
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    90
        else:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    91
            messages.append(inliner.reporter.error(('Invalid field name for API value replacement: "%s".' % text), line=lineno))
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    92
        return [node], messages
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    93
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    94
def find_field_value(role, element_name, field_name):
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    95
    """ Gets the value of a field from an API element. """
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    96
    check_cached_database()
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    97
    
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    98
    field_value = None
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
    99
    element = tree.xml_xpath('//' + roles[role] + "[name='" + element_name + "']")
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   100
    
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   101
    if element != None and len(element) == 1:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   102
        field_value_list = element[0].xml_xpath(field_name)
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   103
        if field_value_list != None and len(field_value_list) == 1:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   104
            field_value = str(field_value_list[0])
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   105
    return field_value
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   106
    
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   107
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   108
def _build_link(text, lineno, inliner, options):
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   109
    """ Build an HTML link to the API doc location for API element. """
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   110
    global exit_with_failure
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   111
    full_path_match = re.search(r"<document source=\"(.*?)\"", str(inliner.document))
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   112
    full_path = full_path_match.group(1)
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   113
    path_segment = full_path[full_path.index('\\doc\\') + 5:]
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   114
    dir_levels = path_segment.count('\\')
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   115
    (parent_type, parent_name) = get_root_element_name(text)
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   116
    messages = []
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   117
    
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   118
    # See if link can be built
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   119
    if parent_type != None and parent_name != None:
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   120
        href_text = text.replace('.', '-').lower()
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   121
        api_path_segment = 'api/helium/' + parent_type + '-' + parent_name  + '.html#' + href_text
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   122
        relative_path = ('../' * dir_levels) + api_path_segment
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   123
        api_doc_path = os.path.abspath(os.path.join(os.getcwd() + '/build/doc', api_path_segment))
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   124
        node = nodes.reference(text, utils.unescape(text), refuri=relative_path, **options)
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   125
        node = nodes.literal(text, '', node, **options)
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   126
    # Or just insert the basic property text
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   127
    else:
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   128
        messages.append(inliner.reporter.error(('Missing API doc for "%s".' % text), line=lineno))
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   129
        node = nodes.literal(text, utils.unescape(text))
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   130
        # Error occurred so record this in order to return the total number as a failure when exiting the program
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   131
        exit_with_failure += 1 
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   132
    return [node], messages
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   133
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   134
def get_root_element_name(text):
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   135
    check_cached_database()
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   136
    
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   137
    if text in treecache:
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   138
        return (treecache[text][1], treecache[text][0])
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   139
    return (None, None)
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   140
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   141
roles = {'hlm-t': 'target',
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   142
         'hlm-p': 'property',
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   143
         'hlm-m': 'macro',}
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   144
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   145
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   146
def setup(app):
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   147
    """ Register custom RST roles for linking Helium targets, properties and macros
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   148
    to the API documentation. """
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   149
    for role in roles.keys():
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   150
        app.add_role(role, handle_hlm_role)
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   151
    app.add_description_unit('property', 'ant-prop', 'pair: %s; property')
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   152
    app.add_description_unit('target', 'ant-target', 'pair: %s; target')
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   153
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents:
diff changeset
   154
    
645
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   155
def check_for_failure():
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   156
    """ Check whether we need to exit the program with a failure due to one or more errors in a custom Sphinx operation. """
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   157
    if exit_with_failure:
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   158
        raise SystemExit("EXCEPTION: Found %d error(s) of type '(ERROR/3) Missing API doc for <property>'" % (exit_with_failure) )
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   159
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   160
# Register a cleanup routine to handle exit with failure
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   161
atexit.register(check_for_failure)
b8d81fa19e7d helium_12.0.0-63b64366f9cf
wbernard
parents: 628
diff changeset
   162