Merge "Improve documentation page layout"

This commit is contained in:
Treehugger Robot 2019-02-20 07:50:16 +00:00 committed by Gerrit Code Review
commit a2b41a6e02
2 changed files with 190 additions and 87 deletions

View file

@ -75,8 +75,7 @@ func main() {
bootstrap.Main(ctx.Context, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName)
if docFile != "" {
err := writeDocs(ctx, docFile)
if err != nil {
if err := writeDocs(ctx, docFile); err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
}

View file

@ -26,7 +26,25 @@ import (
"github.com/google/blueprint/bootstrap/bpdoc"
)
func writeDocs(ctx *android.Context, filename string) error {
type moduleTypeTemplateData struct {
Name string
Synopsis string
Properties []bpdoc.Property
}
// The properties in this map are displayed first, according to their rank.
// TODO(jungjw): consider providing module type-dependent ranking
var propertyRank = map[string]int{
"name": 0,
"src": 1,
"srcs": 2,
"defautls": 3,
"host_supported": 4,
"device_supported": 5,
}
// For each module type, extract its documentation and convert it to the template data.
func moduleTypeDocsToTemplates(ctx *android.Context) ([]moduleTypeTemplateData, error) {
moduleTypeFactories := android.ModuleTypeFactories()
bpModuleTypeFactories := make(map[string]reflect.Value)
for moduleType, factory := range moduleTypeFactories {
@ -35,39 +53,83 @@ func writeDocs(ctx *android.Context, filename string) error {
packages, err := bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories)
if err != nil {
return err
return []moduleTypeTemplateData{}, err
}
buf := &bytes.Buffer{}
var moduleTypeList []*bpdoc.ModuleType
for _, pkg := range packages {
moduleTypeList = append(moduleTypeList, pkg.ModuleTypes...)
}
sort.Slice(moduleTypeList, func(i, j int) bool { return moduleTypeList[i].Name < moduleTypeList[j].Name })
unique := 0
result := make([]moduleTypeTemplateData, 0)
// Combine properties from all PropertyStruct's and reorder them -- first the ones
// with rank, then the rest of the properties in alphabetic order.
for _, m := range moduleTypeList {
item := moduleTypeTemplateData{
Name: m.Name,
Synopsis: m.Text,
Properties: make([]bpdoc.Property, 0),
}
props := make([]bpdoc.Property, 0)
for _, propStruct := range m.PropertyStructs {
props = append(props, propStruct.Properties...)
}
sort.Slice(props, func(i, j int) bool {
if rankI, ok := propertyRank[props[i].Name]; ok {
if rankJ, ok := propertyRank[props[j].Name]; ok {
return rankI < rankJ
} else {
return true
}
}
if _, ok := propertyRank[props[j].Name]; ok {
return false
}
return props[i].Name < props[j].Name
})
// Eliminate top-level duplicates. TODO(jungjw): improve bpdoc to handle this.
previousPropertyName := ""
for _, prop := range props {
if prop.Name == previousPropertyName {
oldProp := &item.Properties[len(item.Properties)-1].Properties
bpdoc.CollapseDuplicateProperties(oldProp, &prop.Properties)
} else {
item.Properties = append(item.Properties, prop)
}
previousPropertyName = prop.Name
}
result = append(result, item)
}
sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
return result, err
}
func writeDocs(ctx *android.Context, filename string) error {
buf := &bytes.Buffer{}
// We need a module name getter/setter function because I couldn't
// find a way to keep it in a variable defined within the template.
currentModuleName := ""
data, err := moduleTypeDocsToTemplates(ctx)
if err != nil {
return err
}
tmpl, err := template.New("file").Funcs(map[string]interface{}{
"unique": func() int {
unique++
return unique
}}).Parse(fileTemplate)
if err != nil {
return err
"setModule": func(moduleName string) string {
currentModuleName = moduleName
return ""
},
"getModule": func() string {
return currentModuleName
},
}).Parse(fileTemplate)
if err == nil {
err = tmpl.Execute(buf, data)
}
err = tmpl.Execute(buf, moduleTypeList)
if err != nil {
return err
if err == nil {
err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
}
err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
if err != nil {
return err
}
return nil
return err
}
const (
@ -75,70 +137,112 @@ const (
<html>
<head>
<title>Build Docs</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
<style>
.accordion,.simple{margin-left:1.5em;text-indent:-1.5em;margin-top:.25em}
.collapsible{border-width:0 0 0 1;margin-left:.25em;padding-left:.25em;border-style:solid;
border-color:grey;display:none;}
span.fixed{display: block; float: left; clear: left; width: 1em;}
ul {
list-style-type: none;
margin: 0;
padding: 0;
width: 30ch;
background-color: #f1f1f1;
position: fixed;
height: 100%;
overflow: auto;
}
li a {
display: block;
color: #000;
padding: 8px 16px;
text-decoration: none;
}
li a.active {
background-color: #4CAF50;
color: white;
}
li a:hover:not(.active) {
background-color: #555;
color: white;
}
</style>
</head>
<body>
<h1>Build Docs</h1>
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
{{range .}}
{{ $collapseIndex := unique }}
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading{{$collapseIndex}}">
<h2 class="panel-title">
<a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse{{$collapseIndex}}" aria-expanded="false" aria-controls="collapse{{$collapseIndex}}">
{{.Name}}
</a>
</h2>
</div>
</div>
<div id="collapse{{$collapseIndex}}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading{{$collapseIndex}}">
<div class="panel-body">
<p>{{.Text}}</p>
{{range .PropertyStructs}}
<p>{{.Text}}</p>
{{template "properties" .Properties}}
{{end}}
</div>
</div>
{{end}}
</div>
</body>
</html>
{{- /* Fixed sidebar with module types */ -}}
<ul>
<li><h3>Module Types:</h3></li>
{{range $moduleType := .}}<li><a href="#{{$moduleType.Name}}">{{$moduleType.Name}}</a></li>
{{end -}}
</ul>
{{/* Main panel with H1 section per module type */}}
<div style="margin-left:30ch;padding:1px 16px;">
<H1>Soong Modules Reference</H1>
The latest versions of Android use the Soong build system, which greatly simplifies build
configuration over the previous Make-based system. This site contains the generated reference
files for the Soong build system.
<p>
See the <a href=https://source.android.com/setup/build/build-system>Android Build System</a>
description for an overview of Soong and examples for its use.
{{define "properties"}}
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
{{range .}}
{{$collapseIndex := unique}}
{{if .Properties}}
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading{{$collapseIndex}}">
<h4 class="panel-title">
<a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse{{$collapseIndex}}" aria-expanded="false" aria-controls="collapse{{$collapseIndex}}">
{{.Name}}{{range .OtherNames}}, {{.}}{{end}}
</a>
</h4>
</div>
</div>
<div id="collapse{{$collapseIndex}}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading{{$collapseIndex}}">
<div class="panel-body">
<p>{{.Text}}</p>
{{range .OtherTexts}}<p>{{.}}</p>{{end}}
{{template "properties" .Properties}}
</div>
</div>
{{else}}
<div>
<h4>{{.Name}}{{range .OtherNames}}, {{.}}{{end}}</h4>
<p>{{.Text}}</p>
{{range .OtherTexts}}<p>{{.}}</p>{{end}}
<p><i>Type: {{.Type}}</i></p>
{{if .Default}}<p><i>Default: {{.Default}}</i></p>{{end}}
</div>
{{end}}
{{end}}
{{range $imodule, $moduleType := .}}
{{setModule $moduleType.Name}}
<p>
<h2 id="{{$moduleType.Name}}">{{$moduleType.Name}}</h2>
{{if $moduleType.Synopsis }}{{$moduleType.Synopsis}}{{else}}<i>Missing synopsis</i>{{end}}
{{- /* Comma-separated list of module attributes' links module attributes */ -}}
<div class="breadcrumb">
{{range $i,$prop := $moduleType.Properties }}
{{ if gt $i 0 }},&nbsp;{{end -}}
<a href=#{{getModule}}.{{$prop.Name}}>{{$prop.Name}}</a>
{{- end -}}
</div>
{{end}}
{{- /* Property description */ -}}
{{- template "properties" $moduleType.Properties -}}
{{- end -}}
{{define "properties" -}}
{{range .}}
{{if .Properties -}}
<div class="accordion" id="{{getModule}}.{{.Name}}">
<span class="fixed">&#x2295</span><b>{{.Name}}</b>
{{- range .OtherNames -}}, {{.}}{{- end -}}
</div>
<div class="collapsible">
{{- .Text}} {{range .OtherTexts}}{{.}}{{end}}
{{template "properties" .Properties -}}
</div>
{{- else -}}
<div class="simple" id="{{getModule}}.{{.Name}}">
<span class="fixed">&nbsp;</span><b>{{.Name}} {{range .OtherNames}}, {{.}}{{end -}}</b>
{{- if .Text -}}{{.Text}}{{- end -}}
{{- with .OtherTexts -}}{{.}}{{- end -}}<i>{{.Type}}</i>
{{- if .Default -}}<i>Default: {{.Default}}</i>{{- end -}}
</div>
{{- end}}
{{- end -}}
{{- end -}}
</div>
<script>
accordions = document.getElementsByClassName('accordion');
for (i=0; i < accordions.length; ++i) {
accordions[i].addEventListener("click", function() {
var panel = this.nextElementSibling;
var child = this.firstElementChild;
if (panel.style.display === "block") {
panel.style.display = "none";
child.textContent = '\u2295';
} else {
panel.style.display = "block";
child.textContent = '\u2296';
}
});
}
</script>
</body>
`
)