github.com/google/capslock@v0.2.3-0.20240517042941-dac19fc347c0/analyzer/scan.go (about) 1 // Copyright 2023 Google LLC 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file or at 5 // https://developers.google.com/open-source/licenses/bsd 6 7 package analyzer 8 9 import ( 10 "embed" 11 "fmt" 12 "go/types" 13 "os" 14 "sort" 15 "strings" 16 "text/template" 17 18 "github.com/fatih/color" 19 "golang.org/x/tools/go/packages" 20 "google.golang.org/protobuf/encoding/protojson" 21 ) 22 23 //go:embed static/* 24 var staticContent embed.FS 25 26 func RunCapslock(args []string, output string, pkgs []*packages.Package, queriedPackages map[*types.Package]struct{}, 27 config *Config) error { 28 if output == "compare" { 29 if len(args) != 1 { 30 return fmt.Errorf("Usage: %s -output=compare <filename>; provided %v args", programName(), len(args)) 31 } 32 compare(args[0], pkgs, queriedPackages, config) 33 } else if len(args) >= 1 { 34 return fmt.Errorf("%s: unknown command", args) 35 } 36 templateFuncMap := template.FuncMap{ 37 "format": templateFormat, 38 } 39 if output == "json" || output == "j" { 40 cil := GetCapabilityInfo(pkgs, queriedPackages, config) 41 b, err := protojson.MarshalOptions{Multiline: true, Indent: "\t"}.Marshal(cil) 42 if err != nil { 43 return fmt.Errorf("internal error: couldn't marshal protocol buffer: %s", err.Error()) 44 } 45 fmt.Println(string(b)) 46 return nil 47 } else if output == "m" || output == "machine" { 48 var cs []string 49 cil := GetCapabilityCounts(pkgs, queriedPackages, config) 50 for c := range cil.CapabilityCounts { 51 cs = append(cs, c) 52 } 53 sort.Strings(cs) 54 for _, c := range cs { 55 fmt.Println(c) 56 } 57 return nil 58 } else if output == "v" || output == "verbose" { 59 cil := GetCapabilityStats(pkgs, queriedPackages, config) 60 ctm := template.Must(template.New("verbose.tmpl").Funcs(templateFuncMap).ParseFS(staticContent, "static/verbose.tmpl")) 61 return ctm.Execute(os.Stdout, cil) 62 } else if output == "g" || output == "graph" { 63 return graphOutput(pkgs, queriedPackages, config) 64 } 65 cil := GetCapabilityCounts(pkgs, queriedPackages, config) 66 ctm := template.Must(template.New("default.tmpl").Funcs(templateFuncMap).ParseFS(staticContent, "static/default.tmpl")) 67 return ctm.Execute(os.Stdout, cil) 68 } 69 70 func templateFormat(args ...interface{}) string { 71 var format string 72 if len(args) != 0 { 73 format = args[0].(string) 74 } 75 var w strings.Builder 76 switch format { 77 case "": 78 // "{{format}}" without arguments resets format. 79 color.New(color.FgHiBlack).UnsetWriter(&w) 80 case "intro", "callpath", "callpath-site": 81 color.New(color.FgHiBlack).SetWriter(&w) 82 case "highlight": 83 color.New(color.FgCyan).SetWriter(&w) 84 case "heading": 85 color.New(color.FgHiWhite).SetWriter(&w) 86 case "nocap": 87 color.New(color.FgHiGreen).SetWriter(&w) 88 case "capability": 89 var capability string 90 if s, ok := args[1].(fmt.Stringer); ok { 91 capability = s.String() 92 } else { 93 capability, ok = args[1].(string) 94 } 95 switch capability { 96 case "CAPABILITY_SAFE": 97 color.New(color.FgHiGreen).SetWriter(&w) 98 case "CAPABILITY_ARBITRARY_EXECUTION", "CAPABILITY_CGO", "CAPABILITY_UNSAFE_POINTER", "CAPABILITY_EXEC": 99 color.New(color.FgHiRed).SetWriter(&w) 100 default: 101 color.New(color.FgHiYellow).SetWriter(&w) 102 } 103 } 104 return w.String() 105 }