k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/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 "os" 24 "path" 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 var resourceDir string 70 if exe, err := os.Executable(); err == nil { 71 resourceDir = path.Join(path.Dir(exe), "cmd/html/static") 72 } else { 73 resourceDir = "gopherage/cmd/html/static" 74 } 75 if _, err := os.Stat(resourceDir); os.IsNotExist(err) { 76 fmt.Fprintf(os.Stderr, "Resource directory %q does not exist. Are you trying to use go run? You must build this program.\n", resourceDir) 77 os.Exit(1) 78 } 79 80 tpl, err := template.ParseFiles(filepath.Join(resourceDir, "browser.html")) 81 if err != nil { 82 fmt.Fprintf(os.Stderr, "Couldn't read the HTML template: %v.", err) 83 os.Exit(1) 84 } 85 script, err := os.ReadFile(filepath.Join(resourceDir, "browser_bundle.es2015.js")) 86 if err != nil { 87 fmt.Fprintf(os.Stderr, "Couldn't read JavaScript: %v.", err) 88 os.Exit(1) 89 } 90 91 // If we're under bazel, move into BUILD_WORKING_DIRECTORY so that manual 92 // invocations of bazel run are less confusing. 93 if wd, ok := os.LookupEnv("BUILD_WORKING_DIRECTORY"); ok { 94 if err := os.Chdir(wd); err != nil { 95 fmt.Fprintf(os.Stderr, "Couldn't chdir into expected working directory.") 96 os.Exit(1) 97 } 98 } 99 100 var coverageFiles []coverageFile 101 for _, arg := range args { 102 var content []byte 103 var err error 104 if arg == "-" { 105 content, err = io.ReadAll(os.Stdin) 106 } else { 107 content, err = os.ReadFile(arg) 108 } 109 if err != nil { 110 fmt.Fprintf(os.Stderr, "Couldn't read coverage file: %v.", err) 111 os.Exit(1) 112 } 113 coverageFiles = append(coverageFiles, coverageFile{Path: arg, Content: string(content)}) 114 } 115 116 outputPath := flags.OutputFile 117 var output io.Writer 118 if outputPath == "-" { 119 output = os.Stdout 120 } else { 121 f, err := os.Create(outputPath) 122 if err != nil { 123 fmt.Fprintf(os.Stderr, "Couldn't open output file: %v.", err) 124 os.Exit(1) 125 } 126 defer f.Close() 127 output = f 128 } 129 130 err = tpl.Execute(output, struct { 131 Script template.JS 132 Coverage []coverageFile 133 }{template.JS(script), coverageFiles}) 134 if err != nil { 135 fmt.Fprintf(os.Stderr, "Couldn't write output file: %v.", err) 136 } 137 }