Split up Soong build doc.

Previously the build doc was a gigantic list of modules and properties,
which can be overwhelming to new users. This change breaks it up by
packages, so that it is easier to look up and feels more coherent.

Bug: 123521276
Test: m soong_docs
Change-Id: I1a1a331f4b4deb8782d698e9076098c5a27b9566
This commit is contained in:
Jaewoong Jung 2019-02-20 07:12:30 -08:00
parent 48db2b15fb
commit 6c29688691
2 changed files with 115 additions and 47 deletions

View File

@ -53,15 +53,19 @@ func (c *docsSingleton) GenerateBuildActions(ctx SingletonContext) {
primaryBuilder := primaryBuilderPath(ctx) primaryBuilder := primaryBuilderPath(ctx)
soongDocs := ctx.Rule(pctx, "soongDocs", soongDocs := ctx.Rule(pctx, "soongDocs",
blueprint.RuleParams{ blueprint.RuleParams{
Command: fmt.Sprintf("%s --soong_docs %s %s", Command: fmt.Sprintf("rm -f ${outDir}/* && %s --soong_docs %s %s",
primaryBuilder.String(), docsFile.String(), strings.Join(os.Args[1:], " ")), primaryBuilder.String(), docsFile.String(), strings.Join(os.Args[1:], " ")),
CommandDeps: []string{primaryBuilder.String()}, CommandDeps: []string{primaryBuilder.String()},
Description: fmt.Sprintf("%s docs $out", primaryBuilder.Base()), Description: fmt.Sprintf("%s docs $out", primaryBuilder.Base()),
}) },
"outDir")
ctx.Build(pctx, BuildParams{ ctx.Build(pctx, BuildParams{
Rule: soongDocs, Rule: soongDocs,
Output: docsFile, Output: docsFile,
Args: map[string]string{
"outDir": PathForOutput(ctx, "docs").String(),
},
}) })
// Add a phony target for building the documentation // Add a phony target for building the documentation

View File

@ -19,6 +19,7 @@ import (
"bytes" "bytes"
"html/template" "html/template"
"io/ioutil" "io/ioutil"
"path/filepath"
"reflect" "reflect"
"sort" "sort"
@ -26,6 +27,11 @@ import (
"github.com/google/blueprint/bootstrap/bpdoc" "github.com/google/blueprint/bootstrap/bpdoc"
) )
type perPackageTemplateData struct {
Name string
Modules []moduleTypeTemplateData
}
type moduleTypeTemplateData struct { type moduleTypeTemplateData struct {
Name string Name string
Synopsis string Synopsis string
@ -44,22 +50,7 @@ var propertyRank = map[string]int{
} }
// For each module type, extract its documentation and convert it to the template data. // For each module type, extract its documentation and convert it to the template data.
func moduleTypeDocsToTemplates(ctx *android.Context) ([]moduleTypeTemplateData, error) { func moduleTypeDocsToTemplates(moduleTypeList []*bpdoc.ModuleType) []moduleTypeTemplateData {
moduleTypeFactories := android.ModuleTypeFactories()
bpModuleTypeFactories := make(map[string]reflect.Value)
for moduleType, factory := range moduleTypeFactories {
bpModuleTypeFactories[moduleType] = reflect.ValueOf(factory)
}
packages, err := bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories)
if err != nil {
return []moduleTypeTemplateData{}, err
}
var moduleTypeList []*bpdoc.ModuleType
for _, pkg := range packages {
moduleTypeList = append(moduleTypeList, pkg.ModuleTypes...)
}
result := make([]moduleTypeTemplateData, 0) result := make([]moduleTypeTemplateData, 0)
// Combine properties from all PropertyStruct's and reorder them -- first the ones // Combine properties from all PropertyStruct's and reorder them -- first the ones
@ -101,39 +92,121 @@ func moduleTypeDocsToTemplates(ctx *android.Context) ([]moduleTypeTemplateData,
result = append(result, item) result = append(result, item)
} }
sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name }) sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
return result, err return result
} }
func writeDocs(ctx *android.Context, filename string) error { func writeDocs(ctx *android.Context, filename string) error {
buf := &bytes.Buffer{} moduleTypeFactories := android.ModuleTypeFactories()
bpModuleTypeFactories := make(map[string]reflect.Value)
for moduleType, factory := range moduleTypeFactories {
bpModuleTypeFactories[moduleType] = reflect.ValueOf(factory)
}
// We need a module name getter/setter function because I couldn't packages, err := bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories)
// find a way to keep it in a variable defined within the template.
currentModuleName := ""
data, err := moduleTypeDocsToTemplates(ctx)
if err != nil { if err != nil {
return err return err
} }
tmpl, err := template.New("file").Funcs(map[string]interface{}{
"setModule": func(moduleName string) string { // Produce the top-level, package list page first.
currentModuleName = moduleName tmpl, err := template.New("file").Parse(packageListTemplate)
return "" if err != nil {
}, return err
"getModule": func() string { }
return currentModuleName buf := &bytes.Buffer{}
},
}).Parse(fileTemplate)
if err == nil { if err == nil {
err = tmpl.Execute(buf, data) err = tmpl.Execute(buf, packages)
} }
if err == nil { if err == nil {
err = ioutil.WriteFile(filename, buf.Bytes(), 0666) err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
} }
// Now, produce per-package module lists with detailed information.
for _, pkg := range packages {
// 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 := ""
tmpl, err := template.New("file").Funcs(map[string]interface{}{
"setModule": func(moduleName string) string {
currentModuleName = moduleName
return ""
},
"getModule": func() string {
return currentModuleName
},
}).Parse(perPackageTemplate)
if err != nil {
return err
}
buf := &bytes.Buffer{}
modules := moduleTypeDocsToTemplates(pkg.ModuleTypes)
data := perPackageTemplateData{Name: pkg.Name, Modules: modules}
err = tmpl.Execute(buf, data)
if err != nil {
return err
}
pkgFileName := filepath.Join(filepath.Dir(filename), pkg.Name+".html")
err = ioutil.WriteFile(pkgFileName, buf.Bytes(), 0666)
if err != nil {
return err
}
}
return err return err
} }
// TODO(jungjw): Consider ordering by name.
const ( const (
fileTemplate = ` packageListTemplate = `
<html>
<head>
<title>Build Docs</title>
<link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/vc67ef93e81a468795c57df87eca3f8427d65cbe85f09fbb51c82a12b89aa3d7e/androidsource/css/app.css">
<style>
#main {
padding: 48px;
}
table{
table-layout: fixed;
}
td {
word-wrap:break-word;
}
</style>
</head>
<body>
<div id="main">
<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.
<table class="module_types" summary="Table of Soong module types sorted by package">
<thead>
<tr>
<th style="width:20%">Package</th>
<th style="width:80%">Module types</th>
</tr>
</thead>
<tbody>
{{range $pkg := .}}
<tr>
<td>{{.Path}}</td>
<td>
{{range $i, $mod := .ModuleTypes}}{{if $i}}, {{end}}<a href="{{$pkg.Name}}.html#{{$mod.Name}}">{{$mod.Name}}</a>{{end}}
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</body>
</html>
`
)
const (
perPackageTemplate = `
<html> <html>
<head> <head>
<title>Build Docs</title> <title>Build Docs</title>
@ -174,21 +247,13 @@ li a:hover:not(.active) {
<body> <body>
{{- /* Fixed sidebar with module types */ -}} {{- /* Fixed sidebar with module types */ -}}
<ul> <ul>
<li><h3>Module Types:</h3></li> <li><h3>{{.Name}} package</h3></li>
{{range $moduleType := .}}<li><a href="#{{$moduleType.Name}}">{{$moduleType.Name}}</a></li> {{range $moduleType := .Modules}}<li><a href="#{{$moduleType.Name}}">{{$moduleType.Name}}</a></li>
{{end -}} {{end -}}
</ul> </ul>
{{/* Main panel with H1 section per module type */}} {{/* Main panel with H1 section per module type */}}
<div style="margin-left:30ch;padding:1px 16px;"> <div style="margin-left:30ch;padding:1px 16px;">
<H1>Soong Modules Reference</H1> {{range $moduleType := .Modules}}
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.
{{range $imodule, $moduleType := .}}
{{setModule $moduleType.Name}} {{setModule $moduleType.Name}}
<p> <p>
<h2 id="{{$moduleType.Name}}">{{$moduleType.Name}}</h2> <h2 id="{{$moduleType.Name}}">{{$moduleType.Name}}</h2>
@ -225,7 +290,6 @@ description for an overview of Soong and examples for its use.
{{- end}} {{- end}}
{{- end -}} {{- end -}}
{{- end -}} {{- end -}}
</div> </div>
<script> <script>
accordions = document.getElementsByClassName('accordion'); accordions = document.getElementsByClassName('accordion');