blob: b4a1ecc1035a44870a1c806bfa5106eca855931c [file] [log] [blame]
# Copyright 2016 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Representations used for rendering documentation templates."""
# internal imports
import os
from skydoc import build_pb2
class Attribute(object):
"""Representation of an attribute used to render documentation templates."""
NAME_LINK = (
'<a href="https://bazel.build/docs/build-ref.html#name">Name</a>')
LABEL_LINK = (
'<a href="https://bazel.build/docs/build-ref.html#labels">Label</a>')
LABELS_LINK = (
'<a href="https://bazel.build/docs/build-ref.html#labels">labels</a>')
def __init__(self, proto):
self.__proto = proto
self.name = proto.name
self.type = self._get_type_str(proto)
if proto.name == 'name' and not proto.documentation:
self.documentation = 'A unique name for this rule.'
else:
self.documentation = proto.documentation
def _get_type_str(self, proto):
type_str = ''
if proto.type == build_pb2.Attribute.INTEGER:
type_str = 'Integer'
elif proto.type == build_pb2.Attribute.STRING:
type_str = 'String'
elif proto.type == build_pb2.Attribute.LABEL:
type_str = self.LABEL_LINK
elif proto.type == build_pb2.Attribute.OUTPUT:
type_str = 'Output'
elif proto.type == build_pb2.Attribute.STRING_LIST:
type_str = 'List of strings'
elif proto.type == build_pb2.Attribute.LABEL_LIST:
type_str = 'List of %s' % self.LABELS_LINK
elif proto.type == build_pb2.Attribute.OUTPUT_LIST:
type_str = 'List of outputs'
elif proto.type == build_pb2.Attribute.DISTRIBUTION_SET:
type_str = 'Distribution Set'
elif proto.type == build_pb2.Attribute.LICENSE:
type_str = 'License'
elif proto.type == build_pb2.Attribute.STRING_DICT:
type_str = 'Dictionary mapping strings to string'
elif proto.type == build_pb2.Attribute.FILESET_ENTRY_LIST:
type_str = 'List of FilesetEntry'
elif proto.type == build_pb2.Attribute.LABEL_LIST_DICT:
type_str = 'Dictionary mapping strings to lists of %s' % self.LABELS_LINK
elif proto.type == build_pb2.Attribute.STRING_LIST_DICT:
type_str = 'Dictionary mapping strings to lists of strings'
elif proto.type == build_pb2.Attribute.BOOLEAN:
type_str = 'Boolean'
elif proto.type == build_pb2.Attribute.TRISTATE:
type_str = 'Tristate'
elif proto.type == build_pb2.Attribute.INTEGER_LIST:
type_str = 'List of integers'
elif proto.type == build_pb2.Attribute.LABEL_DICT_UNARY:
type_str = 'Label Dict Unary'
elif proto.type == build_pb2.Attribute.SELECTOR_LIST:
type_str = 'Selector List'
elif proto.type == build_pb2.Attribute.LABEL_KEYED_STRING_DICT:
type_str = 'Dictionary mapping %s to strings' % self.LABELS_LINK
else:
if proto.name == 'name':
type_str = self.NAME_LINK
else:
type_str = 'Unknown'
type_str += '; Required' if proto.mandatory else '; Optional'
if proto.HasField('default') and not proto.mandatory:
type_str += '; Default is ' + proto.default
return type_str
class Output(object):
"""Representation of an output used to render documentation templates."""
def __init__(self, proto):
self.__proto = proto
self.template = proto.template
self.documentation = proto.documentation
class Rule(object):
"""Representation of a rule used to render documentation templates."""
def __init__(self, proto):
self.__proto = proto
self.name = proto.name
self.type = proto.type
self.documentation = proto.documentation
self.example_documentation = proto.example_documentation
self.signature = self._get_signature(proto)
self.attributes = []
for attribute in proto.attribute:
self.attributes.append(Attribute(attribute))
self.outputs = []
for output in proto.output:
self.outputs.append(Output(output))
parts = proto.documentation.split("\n\n")
self.short_documentation = parts[0]
def _get_signature(self, proto):
"""Returns the rule signature for this rule."""
signature = proto.name + '('
for i in range(len(proto.attribute)):
attr = proto.attribute[i]
signature += '<a href="#%s.%s">%s</a>' % (proto.name, attr.name,
attr.name)
if i < len(proto.attribute) - 1:
signature += ', '
signature += ')'
return signature
class RuleSet(object):
"""Representation of a rule set used to render documentation templates."""
def __init__(self, bzl_file, language, title, description, strip_prefix,
format):
self.bzl_file = bzl_file
file_basename = os.path.basename(bzl_file)
self.name = file_basename.replace('.bzl', '')
self.language = language
self.title = title if title else "%s Rules" % self.name
self.description = description
# Generate output file name.
file_extension = 'html' if format == 'html' else 'md'
assert self.bzl_file.startswith(strip_prefix)
output_path = self.bzl_file.replace('.bzl', '')
self.output_file = output_path[len(strip_prefix):]
# Populate all rules in this ruleset.
self.definitions = []
self.rules = []
self.repository_rules = []
self.macros = []
for rule_proto in language.rule:
definition = Rule(rule_proto)
self.definitions.append(definition)
if rule_proto.type == build_pb2.RuleDefinition.RULE:
self.rules.append(definition)
elif rule_proto.type == build_pb2.RuleDefinition.MACRO:
self.macros.append(definition)
else:
assert rule_proto.type == build_pb2.RuleDefinition.REPOSITORY_RULE
self.repository_rules.append(definition)
def empty(self):
"""Return True if there is nothing to document."""
return not any([self.rules,
self.macros,
self.repository_rules])