blob: d2fbed411b5ef5ce647b8828e9db9462d7761e7a [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 (
Colin Crosse87040b2017-12-11 15:52:26 -080018 "bytes"
19 "html/template"
20 "io/ioutil"
Jaewoong Jung6c296882019-02-20 07:12:30 -080021 "path/filepath"
Colin Cross7089c272019-01-25 22:43:35 -080022 "sort"
Colin Crosse87040b2017-12-11 15:52:26 -080023
Lukacs T. Berkic6012f32021-09-06 18:31:46 +020024 "android/soong/android"
25
Colin Crosse87040b2017-12-11 15:52:26 -080026 "github.com/google/blueprint/bootstrap"
Colin Cross7089c272019-01-25 22:43:35 -080027 "github.com/google/blueprint/bootstrap/bpdoc"
Colin Crosse87040b2017-12-11 15:52:26 -080028)
29
Jaewoong Jung6c296882019-02-20 07:12:30 -080030type perPackageTemplateData struct {
31 Name string
32 Modules []moduleTypeTemplateData
33}
34
Sasha Smundakff483392019-02-07 12:10:56 -080035type moduleTypeTemplateData struct {
36 Name string
Jaewoong Jung238be382019-03-11 14:35:41 -070037 Synopsis template.HTML
Sasha Smundakff483392019-02-07 12:10:56 -080038 Properties []bpdoc.Property
39}
40
41// The properties in this map are displayed first, according to their rank.
42// TODO(jungjw): consider providing module type-dependent ranking
43var propertyRank = map[string]int{
44 "name": 0,
45 "src": 1,
46 "srcs": 2,
Liz Kammere7211dd2020-11-02 22:01:10 +000047 "exclude_srcs": 3,
48 "defaults": 4,
49 "host_supported": 5,
50 "device_supported": 6,
Sasha Smundakff483392019-02-07 12:10:56 -080051}
52
53// For each module type, extract its documentation and convert it to the template data.
Jaewoong Jung6c296882019-02-20 07:12:30 -080054func moduleTypeDocsToTemplates(moduleTypeList []*bpdoc.ModuleType) []moduleTypeTemplateData {
Sasha Smundakff483392019-02-07 12:10:56 -080055 result := make([]moduleTypeTemplateData, 0)
Colin Crosse87040b2017-12-11 15:52:26 -080056
Sasha Smundakff483392019-02-07 12:10:56 -080057 // Combine properties from all PropertyStruct's and reorder them -- first the ones
58 // with rank, then the rest of the properties in alphabetic order.
59 for _, m := range moduleTypeList {
60 item := moduleTypeTemplateData{
61 Name: m.Name,
62 Synopsis: m.Text,
63 Properties: make([]bpdoc.Property, 0),
64 }
65 props := make([]bpdoc.Property, 0)
66 for _, propStruct := range m.PropertyStructs {
67 props = append(props, propStruct.Properties...)
68 }
69 sort.Slice(props, func(i, j int) bool {
70 if rankI, ok := propertyRank[props[i].Name]; ok {
71 if rankJ, ok := propertyRank[props[j].Name]; ok {
72 return rankI < rankJ
73 } else {
74 return true
75 }
76 }
77 if _, ok := propertyRank[props[j].Name]; ok {
78 return false
79 }
80 return props[i].Name < props[j].Name
81 })
82 // Eliminate top-level duplicates. TODO(jungjw): improve bpdoc to handle this.
83 previousPropertyName := ""
84 for _, prop := range props {
85 if prop.Name == previousPropertyName {
86 oldProp := &item.Properties[len(item.Properties)-1].Properties
87 bpdoc.CollapseDuplicateProperties(oldProp, &prop.Properties)
88 } else {
89 item.Properties = append(item.Properties, prop)
90 }
91 previousPropertyName = prop.Name
92 }
93 result = append(result, item)
94 }
95 sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
Jaewoong Jung6c296882019-02-20 07:12:30 -080096 return result
Sasha Smundakff483392019-02-07 12:10:56 -080097}
98
Lukacs T. Berkic6012f32021-09-06 18:31:46 +020099func getPackages(ctx *android.Context) ([]*bpdoc.Package, error) {
Colin Cross9aed5bc2020-12-28 15:15:34 -0800100 moduleTypeFactories := android.ModuleTypeFactoriesForDocs()
Lukacs T. Berkic6012f32021-09-06 18:31:46 +0200101 return bootstrap.ModuleTypeDocs(ctx.Context, moduleTypeFactories)
Jingwen Chend8004ef2020-08-27 09:40:43 +0000102}
Sasha Smundakff483392019-02-07 12:10:56 -0800103
Lukacs T. Berkic6012f32021-09-06 18:31:46 +0200104func writeDocs(ctx *android.Context, filename string) error {
105 packages, err := getPackages(ctx)
Sasha Smundakff483392019-02-07 12:10:56 -0800106 if err != nil {
107 return err
108 }
Jaewoong Jung6c296882019-02-20 07:12:30 -0800109
110 // Produce the top-level, package list page first.
Jaewoong Jung90e11552019-02-22 13:44:38 -0800111 tmpl := template.Must(template.Must(template.New("file").Parse(packageListTemplate)).Parse(copyBaseUrl))
Jaewoong Jung6c296882019-02-20 07:12:30 -0800112 buf := &bytes.Buffer{}
Jaewoong Jung90e11552019-02-22 13:44:38 -0800113 err = tmpl.Execute(buf, packages)
Sasha Smundakff483392019-02-07 12:10:56 -0800114 if err == nil {
115 err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
Colin Crosse87040b2017-12-11 15:52:26 -0800116 }
Jaewoong Jung6c296882019-02-20 07:12:30 -0800117
Andrew Walbran75bba112021-05-07 16:31:30 +0000118 // Now, produce per-package module lists with detailed information, and a list
119 // of keywords.
120 keywordsTmpl := template.Must(template.New("file").Parse(keywordsTemplate))
121 keywordsBuf := &bytes.Buffer{}
Jaewoong Jung6c296882019-02-20 07:12:30 -0800122 for _, pkg := range packages {
123 // We need a module name getter/setter function because I couldn't
124 // find a way to keep it in a variable defined within the template.
125 currentModuleName := ""
Jaewoong Jung90e11552019-02-22 13:44:38 -0800126 tmpl := template.Must(
127 template.Must(template.New("file").Funcs(map[string]interface{}{
128 "setModule": func(moduleName string) string {
129 currentModuleName = moduleName
130 return ""
131 },
132 "getModule": func() string {
133 return currentModuleName
134 },
135 }).Parse(perPackageTemplate)).Parse(copyBaseUrl))
Jaewoong Jung6c296882019-02-20 07:12:30 -0800136 buf := &bytes.Buffer{}
137 modules := moduleTypeDocsToTemplates(pkg.ModuleTypes)
138 data := perPackageTemplateData{Name: pkg.Name, Modules: modules}
139 err = tmpl.Execute(buf, data)
140 if err != nil {
141 return err
142 }
143 pkgFileName := filepath.Join(filepath.Dir(filename), pkg.Name+".html")
144 err = ioutil.WriteFile(pkgFileName, buf.Bytes(), 0666)
145 if err != nil {
146 return err
147 }
Andrew Walbran75bba112021-05-07 16:31:30 +0000148 err = keywordsTmpl.Execute(keywordsBuf, data)
149 if err != nil {
150 return err
151 }
Jaewoong Jung6c296882019-02-20 07:12:30 -0800152 }
Andrew Walbran75bba112021-05-07 16:31:30 +0000153
154 // Write out list of keywords. This includes all module and property names, which is useful for
155 // building syntax highlighters.
156 keywordsFilename := filepath.Join(filepath.Dir(filename), "keywords.txt")
157 err = ioutil.WriteFile(keywordsFilename, keywordsBuf.Bytes(), 0666)
158
Sasha Smundakff483392019-02-07 12:10:56 -0800159 return err
Colin Crosse87040b2017-12-11 15:52:26 -0800160}
161
Jaewoong Jung6c296882019-02-20 07:12:30 -0800162// TODO(jungjw): Consider ordering by name.
Colin Crosse87040b2017-12-11 15:52:26 -0800163const (
Jaewoong Jung6c296882019-02-20 07:12:30 -0800164 packageListTemplate = `
165<html>
166<head>
167<title>Build Docs</title>
Jaewoong Jung6c296882019-02-20 07:12:30 -0800168<style>
169#main {
170 padding: 48px;
171}
172
173table{
174 table-layout: fixed;
175}
176
177td {
178 word-wrap:break-word;
179}
Jaewoong Jung5f867c02019-04-15 15:09:16 -0700180
181/* The following entries are copied from source.android.com's css file. */
182td,td code {
183 color: #202124
184}
185
186th,th code {
187 color: #fff;
188 font: 500 16px/24px Roboto,sans-serif
189}
190
191td,table.responsive tr:not(.alt) td td:first-child,table.responsive td tr:not(.alt) td:first-child {
192 background: rgba(255,255,255,.95);
193 vertical-align: top
194}
195
196td,td code {
197 padding: 7px 8px 8px
198}
199
200tr {
201 border: 0;
202 background: #78909c;
203 border-top: 1px solid #cfd8dc
204}
205
206th,td {
207 border: 0;
208 margin: 0;
209 text-align: left
210}
211
212th {
213 height: 48px;
214 padding: 8px;
215 vertical-align: middle
216}
217
218table {
219 border: 0;
220 border-collapse: collapse;
221 border-spacing: 0;
222 font: 14px/20px Roboto,sans-serif;
223 margin: 16px 0;
224 width: 100%
225}
226
227h1 {
228 color: #80868b;
229 font: 300 34px/40px Roboto,sans-serif;
230 letter-spacing: -0.01em;
231 margin: 40px 0 20px
232}
233
234h1,h2,h3,h4,h5,h6 {
235 overflow: hidden;
236 padding: 0;
237 text-overflow: ellipsis
238}
239
240:link,:visited {
241 color: #039be5;
242 outline: 0;
243 text-decoration: none
244}
245
246body,html {
247 color: #202124;
248 font: 400 16px/24px Roboto,sans-serif;
249 -moz-osx-font-smoothing: grayscale;
250 -webkit-font-smoothing: antialiased;
251 height: 100%;
252 margin: 0;
253 -webkit-text-size-adjust: 100%;
254 -moz-text-size-adjust: 100%;
255 -ms-text-size-adjust: 100%;
256 text-size-adjust: 100%
257}
258
259html {
260 -webkit-box-sizing: border-box;
261 box-sizing: border-box
262}
263
264*,*::before,*::after {
265 -webkit-box-sizing: inherit;
266 box-sizing: inherit
267}
268
269body,div,dl,dd,form,img,input,figure,menu {
270 margin: 0;
271 padding: 0
272}
Jaewoong Jung6c296882019-02-20 07:12:30 -0800273</style>
Jaewoong Jung90e11552019-02-22 13:44:38 -0800274{{template "copyBaseUrl"}}
Jaewoong Jung6c296882019-02-20 07:12:30 -0800275</head>
276<body>
277<div id="main">
278<H1>Soong Modules Reference</H1>
279The latest versions of Android use the Soong build system, which greatly simplifies build
280configuration over the previous Make-based system. This site contains the generated reference
281files for the Soong build system.
282
283<table class="module_types" summary="Table of Soong module types sorted by package">
284 <thead>
285 <tr>
286 <th style="width:20%">Package</th>
287 <th style="width:80%">Module types</th>
288 </tr>
289 </thead>
290 <tbody>
291 {{range $pkg := .}}
292 <tr>
293 <td>{{.Path}}</td>
294 <td>
295 {{range $i, $mod := .ModuleTypes}}{{if $i}}, {{end}}<a href="{{$pkg.Name}}.html#{{$mod.Name}}">{{$mod.Name}}</a>{{end}}
296 </td>
297 </tr>
298 {{end}}
299 </tbody>
300</table>
301</div>
302</body>
303</html>
304`
Jaewoong Jung6c296882019-02-20 07:12:30 -0800305
Jaewoong Jung6c296882019-02-20 07:12:30 -0800306 perPackageTemplate = `
Colin Crosse87040b2017-12-11 15:52:26 -0800307<html>
308<head>
309<title>Build Docs</title>
Sasha Smundakff483392019-02-07 12:10:56 -0800310<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
311<style>
312.accordion,.simple{margin-left:1.5em;text-indent:-1.5em;margin-top:.25em}
313.collapsible{border-width:0 0 0 1;margin-left:.25em;padding-left:.25em;border-style:solid;
314 border-color:grey;display:none;}
315span.fixed{display: block; float: left; clear: left; width: 1em;}
316ul {
317 list-style-type: none;
318 margin: 0;
319 padding: 0;
320 width: 30ch;
321 background-color: #f1f1f1;
322 position: fixed;
323 height: 100%;
324 overflow: auto;
325}
326li a {
327 display: block;
328 color: #000;
329 padding: 8px 16px;
330 text-decoration: none;
331}
332
333li a.active {
334 background-color: #4CAF50;
335 color: white;
336}
337
338li a:hover:not(.active) {
339 background-color: #555;
340 color: white;
341}
342</style>
Jaewoong Jung90e11552019-02-22 13:44:38 -0800343{{template "copyBaseUrl"}}
Colin Crosse87040b2017-12-11 15:52:26 -0800344</head>
345<body>
Sasha Smundakff483392019-02-07 12:10:56 -0800346{{- /* Fixed sidebar with module types */ -}}
347<ul>
Jaewoong Jung6c296882019-02-20 07:12:30 -0800348<li><h3>{{.Name}} package</h3></li>
Jaewoong Jungd10f4842019-02-27 11:15:00 -0800349{{range $moduleType := .Modules}}<li><a href="{{$.Name}}.html#{{$moduleType.Name}}">{{$moduleType.Name}}</a></li>
Sasha Smundakff483392019-02-07 12:10:56 -0800350{{end -}}
351</ul>
352{{/* Main panel with H1 section per module type */}}
353<div style="margin-left:30ch;padding:1px 16px;">
Jaewoong Jung6c296882019-02-20 07:12:30 -0800354{{range $moduleType := .Modules}}
Sasha Smundakff483392019-02-07 12:10:56 -0800355 {{setModule $moduleType.Name}}
356 <p>
357 <h2 id="{{$moduleType.Name}}">{{$moduleType.Name}}</h2>
358 {{if $moduleType.Synopsis }}{{$moduleType.Synopsis}}{{else}}<i>Missing synopsis</i>{{end}}
359 {{- /* Comma-separated list of module attributes' links module attributes */ -}}
360 <div class="breadcrumb">
361 {{range $i,$prop := $moduleType.Properties }}
362 {{ if gt $i 0 }},&nbsp;{{end -}}
Jaewoong Jungd10f4842019-02-27 11:15:00 -0800363 <a href={{$.Name}}.html#{{getModule}}.{{$prop.Name}}>{{$prop.Name}}</a>
Sasha Smundakff483392019-02-07 12:10:56 -0800364 {{- end -}}
Colin Crosse87040b2017-12-11 15:52:26 -0800365 </div>
Sasha Smundakff483392019-02-07 12:10:56 -0800366 {{- /* Property description */ -}}
367 {{- template "properties" $moduleType.Properties -}}
368{{- end -}}
369
370{{define "properties" -}}
371 {{range .}}
372 {{if .Properties -}}
373 <div class="accordion" id="{{getModule}}.{{.Name}}">
374 <span class="fixed">&#x2295</span><b>{{.Name}}</b>
Spandan Daseabda972021-09-12 18:40:37 +0000375 <i>{{.Type}}</i>
Sasha Smundakff483392019-02-07 12:10:56 -0800376 {{- range .OtherNames -}}, {{.}}{{- end -}}
377 </div>
378 <div class="collapsible">
379 {{- .Text}} {{range .OtherTexts}}{{.}}{{end}}
380 {{template "properties" .Properties -}}
381 </div>
382 {{- else -}}
383 <div class="simple" id="{{getModule}}.{{.Name}}">
384 <span class="fixed">&nbsp;</span><b>{{.Name}} {{range .OtherNames}}, {{.}}{{end -}}</b>
Jaewoong Jung12c02a62019-03-12 13:28:25 -0700385 <i>{{.Type}}</i>
386 {{- if .Text -}}{{if ne .Text "\n"}}, {{end}}{{.Text}}{{- end -}}
387 {{- with .OtherTexts -}}{{.}}{{- end -}}
Sasha Smundakff483392019-02-07 12:10:56 -0800388 {{- if .Default -}}<i>Default: {{.Default}}</i>{{- end -}}
389 </div>
390 {{- end}}
391 {{- end -}}
392{{- end -}}
Sasha Smundakff483392019-02-07 12:10:56 -0800393</div>
394<script>
395 accordions = document.getElementsByClassName('accordion');
396 for (i=0; i < accordions.length; ++i) {
397 accordions[i].addEventListener("click", function() {
398 var panel = this.nextElementSibling;
399 var child = this.firstElementChild;
400 if (panel.style.display === "block") {
401 panel.style.display = "none";
402 child.textContent = '\u2295';
403 } else {
404 panel.style.display = "block";
405 child.textContent = '\u2296';
406 }
407 });
408 }
409</script>
410</body>
Colin Crosse87040b2017-12-11 15:52:26 -0800411`
Jaewoong Jung90e11552019-02-22 13:44:38 -0800412
413 copyBaseUrl = `
414{{define "copyBaseUrl"}}
415<script type="text/javascript">
416window.addEventListener('message', (e) => {
417 if (e != null && e.data != null && e.data.type === "SET_BASE" && e.data.base != null) {
418 const existingBase = document.querySelector('base');
419 if (existingBase != null) {
420 existingBase.parentElement.removeChild(existingBase);
421 }
422
423 const base = document.createElement('base');
424 base.setAttribute('href', e.data.base);
425 document.head.appendChild(base);
426 }
427});
428</script>
429{{end}}
430`
Andrew Walbran75bba112021-05-07 16:31:30 +0000431
432 keywordsTemplate = `
433{{range $moduleType := .Modules}}{{$moduleType.Name}}:{{range $property := $moduleType.Properties}}{{$property.Name}},{{end}}
434{{end}}
435`
Colin Crosse87040b2017-12-11 15:52:26 -0800436)