blob: 74c854a39a1a232d3f8b6884b8bb65820c762402 [file] [log] [blame]
Colin Crosse87040b2017-12-11 15:52:26 -08001// Copyright 2017 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package main
16
17import (
18 "android/soong/android"
19 "bytes"
20 "html/template"
21 "io/ioutil"
Colin Cross7089c272019-01-25 22:43:35 -080022 "reflect"
23 "sort"
Colin Crosse87040b2017-12-11 15:52:26 -080024
25 "github.com/google/blueprint/bootstrap"
Colin Cross7089c272019-01-25 22:43:35 -080026 "github.com/google/blueprint/bootstrap/bpdoc"
Colin Crosse87040b2017-12-11 15:52:26 -080027)
28
Sasha Smundakff483392019-02-07 12:10:56 -080029type moduleTypeTemplateData struct {
30 Name string
31 Synopsis string
32 Properties []bpdoc.Property
33}
34
35// The properties in this map are displayed first, according to their rank.
36// TODO(jungjw): consider providing module type-dependent ranking
37var propertyRank = map[string]int{
38 "name": 0,
39 "src": 1,
40 "srcs": 2,
41 "defautls": 3,
42 "host_supported": 4,
43 "device_supported": 5,
44}
45
46// For each module type, extract its documentation and convert it to the template data.
47func moduleTypeDocsToTemplates(ctx *android.Context) ([]moduleTypeTemplateData, error) {
Colin Cross7089c272019-01-25 22:43:35 -080048 moduleTypeFactories := android.ModuleTypeFactories()
49 bpModuleTypeFactories := make(map[string]reflect.Value)
50 for moduleType, factory := range moduleTypeFactories {
51 bpModuleTypeFactories[moduleType] = reflect.ValueOf(factory)
52 }
53
54 packages, err := bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories)
Colin Crosse87040b2017-12-11 15:52:26 -080055 if err != nil {
Sasha Smundakff483392019-02-07 12:10:56 -080056 return []moduleTypeTemplateData{}, err
Colin Crosse87040b2017-12-11 15:52:26 -080057 }
Colin Cross7089c272019-01-25 22:43:35 -080058 var moduleTypeList []*bpdoc.ModuleType
59 for _, pkg := range packages {
60 moduleTypeList = append(moduleTypeList, pkg.ModuleTypes...)
61 }
Colin Cross7089c272019-01-25 22:43:35 -080062
Sasha Smundakff483392019-02-07 12:10:56 -080063 result := make([]moduleTypeTemplateData, 0)
Colin Crosse87040b2017-12-11 15:52:26 -080064
Sasha Smundakff483392019-02-07 12:10:56 -080065 // Combine properties from all PropertyStruct's and reorder them -- first the ones
66 // with rank, then the rest of the properties in alphabetic order.
67 for _, m := range moduleTypeList {
68 item := moduleTypeTemplateData{
69 Name: m.Name,
70 Synopsis: m.Text,
71 Properties: make([]bpdoc.Property, 0),
72 }
73 props := make([]bpdoc.Property, 0)
74 for _, propStruct := range m.PropertyStructs {
75 props = append(props, propStruct.Properties...)
76 }
77 sort.Slice(props, func(i, j int) bool {
78 if rankI, ok := propertyRank[props[i].Name]; ok {
79 if rankJ, ok := propertyRank[props[j].Name]; ok {
80 return rankI < rankJ
81 } else {
82 return true
83 }
84 }
85 if _, ok := propertyRank[props[j].Name]; ok {
86 return false
87 }
88 return props[i].Name < props[j].Name
89 })
90 // Eliminate top-level duplicates. TODO(jungjw): improve bpdoc to handle this.
91 previousPropertyName := ""
92 for _, prop := range props {
93 if prop.Name == previousPropertyName {
94 oldProp := &item.Properties[len(item.Properties)-1].Properties
95 bpdoc.CollapseDuplicateProperties(oldProp, &prop.Properties)
96 } else {
97 item.Properties = append(item.Properties, prop)
98 }
99 previousPropertyName = prop.Name
100 }
101 result = append(result, item)
102 }
103 sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
104 return result, err
105}
106
107func writeDocs(ctx *android.Context, filename string) error {
108 buf := &bytes.Buffer{}
109
110 // We need a module name getter/setter function because I couldn't
111 // find a way to keep it in a variable defined within the template.
112 currentModuleName := ""
113 data, err := moduleTypeDocsToTemplates(ctx)
114 if err != nil {
115 return err
116 }
Colin Crosse87040b2017-12-11 15:52:26 -0800117 tmpl, err := template.New("file").Funcs(map[string]interface{}{
Sasha Smundakff483392019-02-07 12:10:56 -0800118 "setModule": func(moduleName string) string {
119 currentModuleName = moduleName
120 return ""
121 },
122 "getModule": func() string {
123 return currentModuleName
124 },
125 }).Parse(fileTemplate)
126 if err == nil {
127 err = tmpl.Execute(buf, data)
Colin Crosse87040b2017-12-11 15:52:26 -0800128 }
Sasha Smundakff483392019-02-07 12:10:56 -0800129 if err == nil {
130 err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
Colin Crosse87040b2017-12-11 15:52:26 -0800131 }
Sasha Smundakff483392019-02-07 12:10:56 -0800132 return err
Colin Crosse87040b2017-12-11 15:52:26 -0800133}
134
135const (
136 fileTemplate = `
137<html>
138<head>
139<title>Build Docs</title>
Sasha Smundakff483392019-02-07 12:10:56 -0800140<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
141<style>
142.accordion,.simple{margin-left:1.5em;text-indent:-1.5em;margin-top:.25em}
143.collapsible{border-width:0 0 0 1;margin-left:.25em;padding-left:.25em;border-style:solid;
144 border-color:grey;display:none;}
145span.fixed{display: block; float: left; clear: left; width: 1em;}
146ul {
147 list-style-type: none;
148 margin: 0;
149 padding: 0;
150 width: 30ch;
151 background-color: #f1f1f1;
152 position: fixed;
153 height: 100%;
154 overflow: auto;
155}
156li a {
157 display: block;
158 color: #000;
159 padding: 8px 16px;
160 text-decoration: none;
161}
162
163li a.active {
164 background-color: #4CAF50;
165 color: white;
166}
167
168li a:hover:not(.active) {
169 background-color: #555;
170 color: white;
171}
172</style>
Colin Crosse87040b2017-12-11 15:52:26 -0800173</head>
174<body>
Sasha Smundakff483392019-02-07 12:10:56 -0800175{{- /* Fixed sidebar with module types */ -}}
176<ul>
177<li><h3>Module Types:</h3></li>
178{{range $moduleType := .}}<li><a href="#{{$moduleType.Name}}">{{$moduleType.Name}}</a></li>
179{{end -}}
180</ul>
181{{/* Main panel with H1 section per module type */}}
182<div style="margin-left:30ch;padding:1px 16px;">
183<H1>Soong Modules Reference</H1>
184The latest versions of Android use the Soong build system, which greatly simplifies build
185configuration over the previous Make-based system. This site contains the generated reference
186files for the Soong build system.
187<p>
188See the <a href=https://source.android.com/setup/build/build-system>Android Build System</a>
189description for an overview of Soong and examples for its use.
Colin Crosse87040b2017-12-11 15:52:26 -0800190
Sasha Smundakff483392019-02-07 12:10:56 -0800191{{range $imodule, $moduleType := .}}
192 {{setModule $moduleType.Name}}
193 <p>
194 <h2 id="{{$moduleType.Name}}">{{$moduleType.Name}}</h2>
195 {{if $moduleType.Synopsis }}{{$moduleType.Synopsis}}{{else}}<i>Missing synopsis</i>{{end}}
196 {{- /* Comma-separated list of module attributes' links module attributes */ -}}
197 <div class="breadcrumb">
198 {{range $i,$prop := $moduleType.Properties }}
199 {{ if gt $i 0 }},&nbsp;{{end -}}
200 <a href=#{{getModule}}.{{$prop.Name}}>{{$prop.Name}}</a>
201 {{- end -}}
Colin Crosse87040b2017-12-11 15:52:26 -0800202 </div>
Sasha Smundakff483392019-02-07 12:10:56 -0800203 {{- /* Property description */ -}}
204 {{- template "properties" $moduleType.Properties -}}
205{{- end -}}
206
207{{define "properties" -}}
208 {{range .}}
209 {{if .Properties -}}
210 <div class="accordion" id="{{getModule}}.{{.Name}}">
211 <span class="fixed">&#x2295</span><b>{{.Name}}</b>
212 {{- range .OtherNames -}}, {{.}}{{- end -}}
213 </div>
214 <div class="collapsible">
215 {{- .Text}} {{range .OtherTexts}}{{.}}{{end}}
216 {{template "properties" .Properties -}}
217 </div>
218 {{- else -}}
219 <div class="simple" id="{{getModule}}.{{.Name}}">
220 <span class="fixed">&nbsp;</span><b>{{.Name}} {{range .OtherNames}}, {{.}}{{end -}}</b>
221 {{- if .Text -}}{{.Text}}{{- end -}}
222 {{- with .OtherTexts -}}{{.}}{{- end -}}<i>{{.Type}}</i>
223 {{- if .Default -}}<i>Default: {{.Default}}</i>{{- end -}}
224 </div>
225 {{- end}}
226 {{- end -}}
227{{- end -}}
228
229</div>
230<script>
231 accordions = document.getElementsByClassName('accordion');
232 for (i=0; i < accordions.length; ++i) {
233 accordions[i].addEventListener("click", function() {
234 var panel = this.nextElementSibling;
235 var child = this.firstElementChild;
236 if (panel.style.display === "block") {
237 panel.style.display = "none";
238 child.textContent = '\u2295';
239 } else {
240 panel.style.display = "block";
241 child.textContent = '\u2296';
242 }
243 });
244 }
245</script>
246</body>
Colin Crosse87040b2017-12-11 15:52:26 -0800247`
248)