github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/gopherage/cmd/html/html.go (about)

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package html
    18  
    19  import (
    20  	"fmt"
    21  	"html/template"
    22  	"io"
    23  	"io/ioutil"
    24  	"os"
    25  	"path/filepath"
    26  
    27  	"github.com/spf13/cobra"
    28  )
    29  
    30  type flags struct {
    31  	OutputFile string
    32  }
    33  
    34  // MakeCommand returns a `diff` command.
    35  func MakeCommand() *cobra.Command {
    36  	flags := &flags{}
    37  	cmd := &cobra.Command{
    38  		Use:   "html [coverage...]",
    39  		Short: "Emits an HTML file to browse coverage files.",
    40  		Long: `Produces a self-contained HTML file that enables browsing the provided
    41  coverage files by directory. The resulting file can be distributed alone to
    42  produce the same rendering (but does currently require gstatic.com to be
    43  accessible).
    44  
    45  If multiple files are provided, they will all be
    46  shown in the generated HTML file, with the columns in the same order the files
    47  were listed. When there are multiples columns, each column will have an arrow
    48  indicating the change from the column immediately to its right.`,
    49  		Run: func(cmd *cobra.Command, args []string) {
    50  			run(flags, cmd, args)
    51  		},
    52  	}
    53  	cmd.Flags().StringVarP(&flags.OutputFile, "output", "o", "-", "output file")
    54  	return cmd
    55  }
    56  
    57  type coverageFile struct {
    58  	Path    string `json:"path"`
    59  	Content string `json:"content"`
    60  }
    61  
    62  func run(flags *flags, cmd *cobra.Command, args []string) {
    63  	if len(args) < 1 {
    64  		fmt.Println("Expected at least one coverage file.")
    65  		cmd.Usage()
    66  		os.Exit(2)
    67  	}
    68  
    69  	// This path assumes we're being run using bazel.
    70  	resourceDir := "gopherage/cmd/html/static"
    71  	if _, err := os.Stat(resourceDir); os.IsNotExist(err) {
    72  		fmt.Fprintf(os.Stderr, "Resource directory does not exist.")
    73  		os.Exit(1)
    74  	}
    75  
    76  	tpl, err := template.ParseFiles(filepath.Join(resourceDir, "browser.html"))
    77  	if err != nil {
    78  		fmt.Fprintf(os.Stderr, "Couldn't read the HTML template: %v.", err)
    79  		os.Exit(1)
    80  	}
    81  	script, err := ioutil.ReadFile(filepath.Join(resourceDir, "browser_bundle.es6.js"))
    82  	if err != nil {
    83  		fmt.Fprintf(os.Stderr, "Couldn't read JavaScript: %v.", err)
    84  		os.Exit(1)
    85  	}
    86  
    87  	// If we're under bazel, move into BUILD_WORKING_DIRECTORY so that manual
    88  	// invocations of bazel run are less confusing.
    89  	if wd, ok := os.LookupEnv("BUILD_WORKING_DIRECTORY"); ok {
    90  		if err := os.Chdir(wd); err != nil {
    91  			fmt.Fprintf(os.Stderr, "Couldn't chdir into expected working directory.")
    92  			os.Exit(1)
    93  		}
    94  	}
    95  
    96  	var coverageFiles []coverageFile
    97  	for _, arg := range args {
    98  		var content []byte
    99  		var err error
   100  		if arg == "-" {
   101  			content, err = ioutil.ReadAll(os.Stdin)
   102  		} else {
   103  			content, err = ioutil.ReadFile(arg)
   104  		}
   105  		if err != nil {
   106  			fmt.Fprintf(os.Stderr, "Couldn't read coverage file: %v.", err)
   107  			os.Exit(1)
   108  		}
   109  		coverageFiles = append(coverageFiles, coverageFile{Path: arg, Content: string(content)})
   110  	}
   111  
   112  	outputPath := flags.OutputFile
   113  	var output io.Writer
   114  	if outputPath == "-" {
   115  		output = os.Stdout
   116  	} else {
   117  		f, err := os.Create(outputPath)
   118  		if err != nil {
   119  			fmt.Fprintf(os.Stderr, "Couldn't open output file: %v.", err)
   120  			os.Exit(1)
   121  		}
   122  		defer f.Close()
   123  		output = f
   124  	}
   125  
   126  	err = tpl.Execute(output, struct {
   127  		Script   template.JS
   128  		Coverage []coverageFile
   129  	}{template.JS(script), coverageFiles})
   130  	if err != nil {
   131  		fmt.Fprintf(os.Stderr, "Couldn't write output file: %v.", err)
   132  	}
   133  }