Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a2b41a6e authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Improve documentation page layout"

parents aa1491fd ff483393
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -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)
		}
+183 −79
Original line number Diff line number Diff line
@@ -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)

	tmpl, err := template.New("file").Funcs(map[string]interface{}{
		"unique": func() int {
			unique++
			return unique
		}}).Parse(fileTemplate)
	if err != nil {
		return err
	// 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{}

	err = tmpl.Execute(buf, moduleTypeList)
	// 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{}{
		"setModule": func(moduleName string) string {
			currentModuleName = moduleName
			return ""
		},
		"getModule": func() string {
			return currentModuleName
		},
	}).Parse(fileTemplate)
	if err == nil {
		err = tmpl.Execute(buf, data)
	}
	if err == nil {
		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}}
{{- /* 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.

{{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>
</body>
</html>
	{{- /* Property description */ -}}
	{{- template "properties" $moduleType.Properties -}}
{{- end -}}

{{define "properties"}}
  <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
{{define "properties" -}}
  {{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>
    {{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>
        <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}}
    {{- 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>
      {{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}}
  </div>
{{end}}
<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>
`
)