blob: b563bb631b178c38d8882306fadb34cf592d62a9 [file] [log] [blame]
// Copyright 2021 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 program converts a directory of YAML reports produced by `clang_doc` into
// a report usable by test coverage.
//
// Please refer to the file README.md in this directory for more information
// about the program and its use.
package main
import (
"flag"
"fmt"
"io"
"os"
"path/filepath"
"go.fuchsia.dev/fuchsia/sdk/cts/plasa/model"
)
// addAllFromDir scans inputDir for YAML aggregate files and extracts information from them.
// The information is funneled into the supplied function 'add'. The function 'add' is allowed
// to fail, in which case the scanning is stopped.
func addAllFromDir(lenient bool, inputDir string, addFn func(a model.Aggregate) error) error {
err := filepath.WalkDir(inputDir, func(path string, d os.DirEntry, err error) error {
if err != nil {
return fmt.Errorf("filepath.WalkDir called with err != nil:\n\t%w", err)
}
if d.IsDir() {
return nil
}
f, err := os.Open(path)
if err != nil {
return fmt.Errorf("while opening: %v:\n\t%w", path, err)
}
a, err := model.ParseYAML(f, lenient)
if err != nil {
return fmt.Errorf("while parsing: %v:\n\t%w", path, err)
}
if err := addFn(a); err != nil {
return fmt.Errorf("while adding aggregate: %+v:\n\t%w", a, err)
}
return nil
})
if err != nil {
return fmt.Errorf("somewhere in the input directory: %v\n\t%w", inputDir, err)
}
return nil
}
// run executes the report generator on all files in the directory inputDir,
// and writes a report into the supplied writer.
func run(inputDir string, w io.Writer, args args) error {
var r model.Report
r.SetFileRegexes(args.allowlistFilenameRegexp)
r.SetSymRegexes(args.allowlistNameRegexp)
if err := addAllFromDir(args.lenient, inputDir, r.AddAggregate); err != nil {
return fmt.Errorf("in main.run(): while reading dir:\n\t%w", err)
}
if err := r.WriteJSON(w); err != nil {
return fmt.Errorf("in main.run(): while writing output file:\n\t%w", err)
}
return nil
}
// args contains the settings which will be initialized from command line arguments.
type args struct {
inputDir string
outFile string
allowlistFilenameRegexp []string
allowlistNameRegexp []string
lenient bool
}
func (a *args) addAllowlistFnRegexp(s string) error {
a.allowlistFilenameRegexp = append(a.allowlistFilenameRegexp, s)
return nil
}
func (a *args) addAlowlistSymRegexp(s string) error {
a.allowlistNameRegexp = append(a.allowlistNameRegexp, s)
return nil
}
func main() {
var args args
flag.StringVar(&args.inputDir, "input-dir", "", "the input directory to get the files from")
flag.StringVar(&args.outFile, "output-file", "", "the file to write the final report to")
flag.BoolVar(&args.lenient, "lenient", false, "if set, reading YAML will not produce an error.")
flag.Func("allow-filename-regexp",
"a regexp that may match any part of the filename; if unset, no filtering will take place",
args.addAllowlistFnRegexp)
flag.Func("allow-symbol-name-regexp",
"a regexp that may match any part of the symbol name; if unset, no filtering will take place",
args.addAllowlistFnRegexp)
flag.Parse()
if args.inputDir == "" {
fmt.Fprintf(os.Stderr, "the flag --input-dir=... is required")
os.Exit(-1)
}
if args.outFile == "" {
fmt.Fprintf(os.Stderr, "the flag --output-file=... is required")
os.Exit(-1)
}
of, err := os.Create(args.outFile)
if err != nil {
fmt.Fprintf(os.Stderr, "error while opening output file: %v:\n\t%v\n", args.outFile, err)
os.Exit(-1)
}
if err := run(args.inputDir, of, args); err != nil {
fmt.Fprintf(os.Stderr, "error while writing output file: %v:\n\t%v\n", args.outFile, err)
os.Exit(-1)
}
}