diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 1f6002ee2..41c7d46ce 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -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) } diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go index 8f86b3321..74c854a39 100644 --- a/cmd/soong_build/writedocs.go +++ b/cmd/soong_build/writedocs.go @@ -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 (
{{.Text}}
- {{range .PropertyStructs}} -{{.Text}}
- {{template "properties" .Properties}} - {{end}} -+See the Android Build System +description for an overview of Soong and examples for its use. -{{define "properties"}} -
{{.Text}}
- {{range .OtherTexts}}{{.}}
{{end}} - {{template "properties" .Properties}} -{{.Text}}
- {{range .OtherTexts}}{{.}}
{{end}} -Type: {{.Type}}
- {{if .Default}}Default: {{.Default}}
{{end}} -+