Merge "Improve documentation page layout"
This commit is contained in:
commit
a2b41a6e02
2 changed files with 190 additions and 87 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 }}, {{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">⊕</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"> </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>
|
||||
`
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue