| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This file implements output formatting for the cobalt config parser. |
| |
| package config_parser |
| |
| import ( |
| "bytes" |
| "config" |
| "encoding/base64" |
| "fmt" |
| "github.com/golang/protobuf/proto" |
| "strings" |
| ) |
| |
| type OutputFormatter func(c *config.CobaltConfig) (outputBytes []byte, err error) |
| |
| // Outputs the serialized proto. |
| func BinaryOutput(c *config.CobaltConfig) (outputBytes []byte, err error) { |
| return proto.Marshal(c) |
| } |
| |
| // Outputs the serialized proto base64 encoded. |
| func Base64Output(c *config.CobaltConfig) (outputBytes []byte, err error) { |
| configBytes, err := BinaryOutput(c) |
| if err != nil { |
| return outputBytes, err |
| } |
| encoder := base64.StdEncoding |
| outLen := encoder.EncodedLen(len(configBytes)) |
| |
| outputBytes = make([]byte, outLen, outLen) |
| encoder.Encode(outputBytes, configBytes) |
| return outputBytes, nil |
| } |
| |
| // writeIdConstants prints out a list of constants to be used in testing. It |
| // uses the Name attribute of each Metric, Report, and Encoding to construct the |
| // constants. |
| // |
| // For a metric named "SingleString" the constant would be kSingleStringMetricId |
| // For a report named "Test" the constant would be kTestReportId |
| // For an encoding named "Forculus" the canstant would be kForculusEncodingId |
| func writeIdConstants(out *bytes.Buffer, constType string, entries map[string]uint32) { |
| if len(entries) == 0 { |
| return |
| } |
| out.WriteString(fmt.Sprintf("// %s ID Constants\n", constType)) |
| for name, id := range entries { |
| name = strings.Join(strings.Split(name, " "), "") |
| out.WriteString(fmt.Sprintf("const uint32_t k%s%sId = %d;\n", name, constType, id)) |
| } |
| out.WriteString("\n") |
| } |
| |
| // Returns an output formatter that will output the contents of a C++ header |
| // file that contains a variable declaration for a string literal that contains |
| // the base64-encoding of the serialized proto. |
| // |
| // varName will be the name of the variable containing the base64-encoded serialized proto. |
| // namespace is a list of nested namespaces inside of which the variable will be defined. |
| // configLocation is the location of the YAML that was parsed. |
| func CppOutputFactory(varName string, namespace []string, configLocation string) OutputFormatter { |
| return func(c *config.CobaltConfig) (outputBytes []byte, err error) { |
| b64Bytes, err := Base64Output(c) |
| if err != nil { |
| return outputBytes, err |
| } |
| |
| out := new(bytes.Buffer) |
| out.WriteString("// Copyright 2018 The Fuchsia Authors. All rights reserved.\n") |
| out.WriteString("// Use of this source code is governed by a BSD-style license that can be\n") |
| out.WriteString("// found in the LICENSE file.\n\n") |
| out.WriteString("#pragma once\n\n") |
| out.WriteString("// This file was generated by Cobalt's Config Parser based on the\n") |
| out.WriteString("// configuration YAML in the following location:\n") |
| out.WriteString(fmt.Sprintf("// %s\n", configLocation)) |
| out.WriteString("// Edit the YAML at that location to make changes.\n\n") |
| |
| for _, name := range namespace { |
| out.WriteString("namespace ") |
| out.WriteString(name) |
| out.WriteString(" {\n") |
| } |
| |
| metrics := make(map[string]uint32) |
| for _, metric := range c.MetricConfigs { |
| if metric.Name != "" { |
| if _, ok := metrics[metric.Name]; ok { |
| return outputBytes, fmt.Errorf("Duplicate metric name found %v", metric.Name) |
| } |
| metrics[metric.Name] = metric.Id |
| } |
| } |
| // Write out the 'Metric' constants (e.g. kTestMetricId) |
| writeIdConstants(out, "Metric", metrics) |
| |
| reports := make(map[string]uint32) |
| for _, report := range c.ReportConfigs { |
| if report.Name != "" { |
| if _, ok := reports[report.Name]; ok { |
| return outputBytes, fmt.Errorf("Duplicate report name found %v", report.Name) |
| } |
| reports[report.Name] = report.Id |
| } |
| } |
| // Write out the 'Report' constants (e.g. kTestReportId) |
| writeIdConstants(out, "Report", reports) |
| |
| encodings := make(map[string]uint32) |
| for _, encoding := range c.EncodingConfigs { |
| if encoding.Name != "" { |
| if _, ok := encodings[encoding.Name]; ok { |
| return outputBytes, fmt.Errorf("Duplicate encoding name found %v", encoding.Name) |
| } |
| encodings[encoding.Name] = encoding.Id |
| } |
| } |
| // Write out the 'Encoding' constants (e.g. kTestEncodingId) |
| writeIdConstants(out, "Encoding", encodings) |
| |
| out.WriteString("// The base64 encoding of the bytes of a serialized CobaltConfig proto message.\n") |
| out.WriteString("const char ") |
| out.WriteString(varName) |
| out.WriteString("[] = \"") |
| out.Write(b64Bytes) |
| out.WriteString("\";\n") |
| |
| for _, name := range namespace { |
| out.WriteString("} // ") |
| out.WriteString(name) |
| out.WriteString("\n") |
| } |
| return out.Bytes(), nil |
| } |
| } |
| |
| // Returns an output formatter that will output the contents of a Dart file |
| // that contains a variable declaration for a string literal that contains |
| // the base64-encoding of the serialized proto. |
| // |
| // varName will be the name of the variable containing the base64-encoded serialized proto. |
| // namespace is a list of nested namespaces inside of which the variable will be defined. |
| // configLocation is the location of the YAML that was parsed. |
| func DartOutputFactory(varName string, configLocation string) OutputFormatter { |
| return func(c *config.CobaltConfig) (outputBytes []byte, err error) { |
| b64Bytes, err := Base64Output(c) |
| if err != nil { |
| return outputBytes, err |
| } |
| |
| out := new(bytes.Buffer) |
| out.WriteString("// Copyright 2018 The Fuchsia Authors. All rights reserved.\n") |
| out.WriteString("// Use of this source code is governed by a BSD-style license that can be\n") |
| out.WriteString("// found in the LICENSE file.\n\n") |
| out.WriteString("// This file was generated by Cobalt's Config Parser based on the\n") |
| out.WriteString("// configuration YAML in the following location:\n") |
| out.WriteString(fmt.Sprintf("// %s\n", configLocation)) |
| out.WriteString("// Edit the YAML at that location to make changes.\n\n") |
| |
| out.WriteString("// The base64 encoding of the bytes of a serialized CobaltConfig proto message.\n") |
| out.WriteString("const String ") |
| out.WriteString(varName) |
| out.WriteString(" = '") |
| out.Write(b64Bytes) |
| out.WriteString("';\n") |
| |
| return out.Bytes(), nil |
| } |
| } |