1
15
16
17
18
19
20 package main
21
22 import (
23 "bufio"
24 "bytes"
25 "encoding/csv"
26 "flag"
27 "fmt"
28 "go/format"
29 "log"
30 "os"
31 "path/filepath"
32 "text/template"
33
34 "github.com/bazelbuild/bazel-gazelle/label"
35 )
36
37 var progName = filepath.Base(os.Args[0])
38
39 var knownImportsTpl = template.Must(template.New("known_imports.go").Parse(`
40 // Generated by language/proto/gen/gen_known_imports.go
41 // From {{.ProtoCsv}}
42
43 package {{.Package}}
44
45 import "github.com/bazelbuild/bazel-gazelle/label"
46
47 var {{.Var}} = map[string]label.Label{
48 {{range .Bindings}}
49 {{printf "%q: label.Label{Repo: %q, Pkg: %q, Name: %q}" .Import .Label.Repo .Label.Pkg .Label.Name}},
50 {{- end}}
51 }
52 `))
53
54 type data struct {
55 ProtoCsv, Package, Var string
56 Bindings []binding
57 }
58
59 type binding struct {
60 Import string
61 Label label.Label
62 }
63
64 func main() {
65 log.SetPrefix(progName + ": ")
66 log.SetFlags(0)
67 if err := run(os.Args[1:]); err != nil {
68 log.Fatal(err)
69 }
70 }
71
72 func run(args []string) (err error) {
73 fs := flag.NewFlagSet(progName, flag.ExitOnError)
74 var protoCsvPath, knownImportsPath, package_, var_ string
75 var keyColumn, valueColumn int
76 fs.StringVar(&protoCsvPath, "proto_csv", "", "path to proto.csv input file")
77 fs.StringVar(&knownImportsPath, "known_imports", "", "path to known_imports.go output file")
78 fs.StringVar(&package_, "package", "", "package name in generated file")
79 fs.StringVar(&var_, "var", "", "var name in generated file")
80 fs.IntVar(&keyColumn, "key", 0, "key column number")
81 fs.IntVar(&valueColumn, "value", 1, "value column number")
82 if err = fs.Parse(args); err != nil {
83 return fmt.Errorf("invalid flag: %v", err)
84 }
85 if protoCsvPath == "" {
86 return fmt.Errorf("-proto_csv not set")
87 }
88 if knownImportsPath == "" {
89 return fmt.Errorf("-known_imports not set")
90 }
91 if package_ == "" {
92 return fmt.Errorf("-package not set")
93 }
94 if var_ == "" {
95 return fmt.Errorf("-var not set")
96 }
97
98 protoCsvFile, err := os.Open(protoCsvPath)
99 if err != nil {
100 return err
101 }
102 r := csv.NewReader(bufio.NewReader(protoCsvFile))
103 r.Comment = '#'
104 r.FieldsPerRecord = 4
105 records, err := r.ReadAll()
106 protoCsvFile.Close()
107 if err != nil {
108 return err
109 }
110 data := data{
111 ProtoCsv: protoCsvPath,
112 Package: package_,
113 Var: var_,
114 }
115 seen := make(map[string]label.Label)
116 for _, rec := range records {
117 imp := rec[keyColumn]
118 lbl, err := label.Parse(rec[valueColumn])
119 if err != nil {
120 return err
121 }
122 if seenLabel, ok := seen[imp]; ok {
123 if !seenLabel.Equal(lbl) {
124 return fmt.Errorf("for key %s, multiple values (%s and %s)", imp, seenLabel, lbl)
125 }
126 continue
127 }
128 seen[imp] = lbl
129 data.Bindings = append(data.Bindings, binding{imp, lbl})
130 }
131
132 knownImportsBuf := &bytes.Buffer{}
133 if err := knownImportsTpl.Execute(knownImportsBuf, data); err != nil {
134 return err
135 }
136 knownImportsData, err := format.Source(knownImportsBuf.Bytes())
137 if err != nil {
138 return err
139 }
140 if err := os.WriteFile(knownImportsPath, knownImportsData, 0o666); err != nil {
141 return err
142 }
143
144 return nil
145 }
146
View as plain text