| // Copyright 2019 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 contains flag definitions for the source_generator package as well |
| // as all the functions which make direct use of these flags. |
| package source_generator |
| |
| import ( |
| "config" |
| "flag" |
| "fmt" |
| "os" |
| "privacy" |
| "strings" |
| ) |
| |
| var ( |
| addFileSuffix = flag.Bool("add_file_suffix", false, "Append the out_format to the out_file, even if there is only one out_format specified") |
| outFile = flag.String("output_file", "", "File to which the serialized config should be written. Defaults to stdout. When multiple output formats are specified, it will append the format to the filename") |
| outFilename = flag.String("out_filename", "", "The base name to use for writing files. Should not be used with output_file.") |
| outDir = flag.String("out_dir", "", "The directory into which files should be written.") |
| outFormat = flag.String("out_format", "bin", "Specifies the output formats (separated by ' '). Supports 'bin' (serialized proto), 'go' (a golang package), 'b64' (serialized proto to base 64), 'cpp' (a C++ file containing a variable with a base64-encoded serialized proto) 'dart' (a Dart library), 'json' (a JSON object), and 'rust' (a rust crate)") |
| features = flag.String("features", "", "A comma separated list of source generator features to enable.") |
| namespace = flag.String("namespace", "", "When using the 'cpp', 'rust', or 'go' output format, this will specify the period-separated namespace within which the config variable must be placed (this will be transformed into an underscore-separated package name for go).") |
| goPackageName = flag.String("go_package", "", "When using the 'go' output format, this will specify the package for generated code.") |
| dartOutDir = flag.String("dart_out_dir", "", "The directory to write dart files to (if different from out_dir)") |
| varName = flag.String("var_name", "config", "When using the 'cpp' or 'dart' output format, this will specify the variable name to be used in the output.") |
| privacyParamsPath = flag.String("privacy_params_path", "", "For output formats that require an error estimate, this specifies the path to a file containing required privacy parameters.") |
| checkOnly = flag.Bool("check_only", false, "Only check that the configuration is valid.") |
| allowEmptyOutput = flag.Bool("allow_empty_output", false, "Relax the requirement that the cobalt registry output not be empty.") |
| ) |
| |
| // checkFlags verifies that the specified flags are compatible with each other. |
| func checkFlags() error { |
| if *outFile != "" && *checkOnly { |
| return fmt.Errorf("'output_file' does not make sense if 'check_only' is set.") |
| } |
| |
| if *outFile != "" && *outFilename != "" { |
| return fmt.Errorf("-output_file and -out_filename are mutually exclusive.") |
| } |
| |
| if (*outDir != "" || *dartOutDir != "") && *outFile != "" { |
| return fmt.Errorf("-output_file should not be set at the same time as -out_dir or -dart_out_dir") |
| } |
| |
| if (*outDir != "" || *dartOutDir != "") && *outFilename == "" { |
| return fmt.Errorf("-out_dir or -dart_out_dir require specifying -out_filename.") |
| } |
| |
| for _, format := range parseOutFormatList(*outFormat) { |
| if format == "go" { |
| if *goPackageName == "" { |
| return fmt.Errorf("-go_package must be specified for the go output format") |
| } |
| } |
| } |
| return nil |
| } |
| |
| func filenameGeneratorFromFlags() func(string) string { |
| return getFilenameGenerator(*outFile, *outFilename, *outDir, *dartOutDir) |
| } |
| |
| // WriteDepFileFromFlags writes a depfile to the location specified in depFile. |
| // files must be a list of the reigstry input files. |
| func WriteDepFileFromFlags(files []string, depFile string) error { |
| if *outFile == "" && *outFilename == "" { |
| return fmt.Errorf("-dep_file requires -output_file or -out_filename") |
| } |
| |
| w, err := os.Create(depFile) |
| if err != nil { |
| return err |
| } |
| defer w.Close() |
| |
| return writeDepFile(parseOutFormatList(*outFormat), files, filenameGeneratorFromFlags(), w) |
| } |
| |
| // WriteConfigFromFlags writes the specified CobaltRegistry according to the |
| // flags specified above. |
| func WriteConfigFromFlags(c, filtered *config.CobaltRegistry) error { |
| if err := checkFlags(); err != nil { |
| return err |
| } |
| |
| var errorCalc *privacy.ErrorCalculator |
| if *privacyParamsPath != "" { |
| var err error |
| errorCalc, err = privacy.NewErrorCalculatorFromPrivacyParams(*privacyParamsPath) |
| if err != nil { |
| return err |
| } |
| } |
| |
| generateFilename := filenameGeneratorFromFlags() |
| features := strings.Split(*features, ",") |
| for _, format := range parseOutFormatList(*outFormat) { |
| outputFormatter, err := getOutputFormatter(format, *namespace, *goPackageName, *varName, features, *outFilename, errorCalc) |
| if err != nil { |
| return err |
| } |
| |
| // Then, we serialize the configuration. |
| configBytes, err := outputFormatter(c, filtered) |
| if err != nil { |
| return err |
| } |
| |
| // Check that the output file is not empty. |
| if !*allowEmptyOutput && len(configBytes) == 0 { |
| return fmt.Errorf("Output file is empty.") |
| } |
| |
| // If no errors have occurred yet and checkOnly was set, we don't need to write anything. |
| if *checkOnly { |
| continue |
| } |
| |
| // By default we print the output to stdout. |
| w := os.Stdout |
| |
| if *outFile != "" || *outFilename != "" { |
| fname := generateFilename(format) |
| w, err = os.Create(fname) |
| if err != nil { |
| return err |
| } |
| } |
| |
| if _, err := w.Write(configBytes); err != nil { |
| return err |
| } |
| } |
| if *checkOnly { |
| fmt.Printf("OK\n") |
| } |
| return nil |
| } |