github.com/stackb/rules_proto@v0.0.0-20240221195024-5428336c51f1/pkg/plugintest/utils.go (about) 1 package plugintest 2 3 import ( 4 "log" 5 "os" 6 "os/exec" 7 "path/filepath" 8 "testing" 9 10 "github.com/bazelbuild/bazel-gazelle/label" 11 "github.com/bazelbuild/bazel-gazelle/rule" 12 "github.com/stackb/rules_proto/pkg/protoc" 13 ) 14 15 // PluginConfigurationOption modifies a configuration in-place 16 type PluginConfigurationOption func(c *protoc.PluginConfiguration) 17 18 // WithConfiguration creates a new PluginConfiguration and applies all the given 19 // options. 20 func WithConfiguration(options ...PluginConfigurationOption) *protoc.PluginConfiguration { 21 c := &protoc.PluginConfiguration{} 22 for _, opt := range options { 23 opt(c) 24 } 25 return c 26 } 27 28 // WithOutputs assigns the Outputs field. 29 func WithOutputs(outputs ...string) PluginConfigurationOption { 30 return func(c *protoc.PluginConfiguration) { 31 c.Outputs = outputs 32 } 33 } 34 35 // WithOptions assigns the Options field. 36 func WithOptions(options ...string) PluginConfigurationOption { 37 return func(c *protoc.PluginConfiguration) { 38 c.Options = options 39 } 40 } 41 42 // WithOut assigns the Out field. 43 func WithOut(out string) PluginConfigurationOption { 44 return func(c *protoc.PluginConfiguration) { 45 c.Out = out 46 } 47 } 48 49 // WithLabel assigns the Label field. 50 func WithLabel(t *testing.T, raw string) PluginConfigurationOption { 51 return func(c *protoc.PluginConfiguration) { 52 lbl, err := label.Parse(raw) 53 if err != nil { 54 t.Fatalf("bad label %q: %v", raw, err) 55 } 56 c.Label = lbl 57 } 58 } 59 60 // WithDirectives assigns rule Directives. 61 func WithDirectives(items ...string) (d []rule.Directive) { 62 if len(items)%2 != 0 { 63 panic("directive list must be a sequence of key/value pairs") 64 } 65 if len(items) < 2 { 66 return 67 } 68 for i := 1; i < len(items); i = i + 2 { 69 d = append(d, rule.Directive{Key: items[i-1], Value: items[i]}) 70 } 71 return 72 } 73 74 func mustExecProtoc(t *testing.T, protoc, dir string, env []string, args ...string) { 75 cmd := exec.Command(protoc, args...) 76 cmd.Dir = dir 77 cmd.Env = env 78 out, err := cmd.CombinedOutput() 79 if err != nil { 80 t.Fatalf("protoc exec error: %v\n\n%s", err, out) 81 } 82 } 83 84 // mustListFiles - convenience debugging function to log the files under a given 85 // dir, excluding proto files and the extra binaries here. 86 func mustListFiles(t *testing.T, dir string) []string { 87 files := make([]string, 0) 88 89 if err := filepath.Walk(dir, func(relname string, info os.FileInfo, err error) error { 90 if err != nil { 91 t.Fatal(err) 92 } 93 if info.IsDir() { 94 return nil 95 } 96 if filepath.Ext(relname) == ".proto" { 97 return nil 98 } 99 files = append(files, relname) 100 return nil 101 }); err != nil { 102 t.Fatal(err) 103 } 104 105 return files 106 } 107 108 // fileExists checks if a file exists and is not a directory before we try using 109 // it to prevent further errors. 110 func fileExists(filename string) bool { 111 info, err := os.Stat(filename) 112 if os.IsNotExist(err) { 113 return false 114 } 115 if info == nil { 116 return false 117 } 118 return !info.IsDir() 119 } 120 121 // listFiles - convenience debugging function to log the files under a given dir 122 func listFiles(dir string) error { 123 return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 124 if err != nil { 125 log.Printf("%v\n", err) 126 return err 127 } 128 if info.Mode()&os.ModeSymlink > 0 { 129 link, err := os.Readlink(path) 130 if err != nil { 131 return err 132 } 133 log.Printf("%s -> %s", path, link) 134 return nil 135 } 136 137 log.Println(path) 138 return nil 139 }) 140 }