blob: 3557b8e19733d13b5594be6e6fd455b16078a1e6 [file] [log] [blame]
// 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
}
}