1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package main
30
31 import (
32 "bufio"
33 "bytes"
34 "flag"
35 "fmt"
36 "io/ioutil"
37 "os"
38 "os/exec"
39 "path/filepath"
40 "strings"
41
42 "github.com/gogo/protobuf/version"
43 )
44
45 type MixMatch struct {
46 Old []string
47 Filename string
48 Args []string
49 }
50
51 func (this MixMatch) Gen(folder string, news []string) {
52 if err := os.MkdirAll(folder, 0777); err != nil {
53 panic(err)
54 }
55 data, err := ioutil.ReadFile(this.Filename)
56 if err != nil {
57 panic(err)
58 }
59 content := string(data)
60 for i, old := range this.Old {
61 if !strings.Contains(content, old) {
62 panic(fmt.Errorf("could not find string {%s} to replace with {%s}", old, news[i]))
63 }
64 content = strings.Replace(content, old, news[i], 1)
65 if strings.Contains(content, old) && old != news[i] {
66 panic(fmt.Errorf("found another string {%s} after it was replaced with {%s}", old, news[i]))
67 }
68 }
69 if err = ioutil.WriteFile(filepath.Join(folder, this.Filename), []byte(content), 0666); err != nil {
70 panic(err)
71 }
72 args := append(this.Args, filepath.Join(folder, this.Filename))
73 var regenerate = exec.Command("protoc", args...)
74 out, err := regenerate.CombinedOutput()
75
76 failed := false
77 scanner := bufio.NewScanner(bytes.NewReader(out))
78 for scanner.Scan() {
79 text := scanner.Text()
80 fmt.Println("protoc-gen-combo: ", text)
81 if !strings.Contains(text, "WARNING") {
82 failed = true
83 }
84 }
85
86 if err != nil {
87 fmt.Print("protoc-gen-combo: error: ", err)
88 failed = true
89 }
90
91 if failed {
92 os.Exit(1)
93 }
94 }
95
96 func filter(ss []string, flag string) ([]string, string) {
97 s := make([]string, 0, len(ss))
98 var v string
99 for i := range ss {
100 if strings.Contains(ss[i], flag) {
101 vs := strings.Split(ss[i], "=")
102 v = vs[1]
103 continue
104 }
105 s = append(s, ss[i])
106 }
107 return s, v
108 }
109
110 func filterArgs(ss []string) ([]string, []string) {
111 var args []string
112 var flags []string
113 for i := range ss {
114 if strings.Contains(ss[i], "=") {
115 flags = append(flags, ss[i])
116 continue
117 }
118 args = append(args, ss[i])
119 }
120 return flags, args
121 }
122
123 func main() {
124 flag.String("version", "2.3.0", "minimum protoc version")
125 flag.Bool("default", true, "generate the case where everything is false")
126 flags, args := filterArgs(os.Args[1:])
127 var min string
128 flags, min = filter(flags, "-version")
129 if len(min) == 0 {
130 min = "2.3.1"
131 }
132 if !version.AtLeast(min) {
133 fmt.Printf("protoc version not high enough to parse this proto file\n")
134 return
135 }
136 if len(args) != 1 {
137 fmt.Printf("protoc-gen-combo expects a filename\n")
138 os.Exit(1)
139 }
140 filename := args[0]
141 var def string
142 flags, def = filter(flags, "-default")
143 if _, err := exec.LookPath("protoc"); err != nil {
144 panic("cannot find protoc in PATH")
145 }
146 m := MixMatch{
147 Old: []string{
148 "option (gogoproto.unmarshaler_all) = false;",
149 "option (gogoproto.marshaler_all) = false;",
150 },
151 Filename: filename,
152 Args: flags,
153 }
154 if def != "false" {
155 m.Gen("./combos/neither/", []string{
156 "option (gogoproto.unmarshaler_all) = false;",
157 "option (gogoproto.marshaler_all) = false;",
158 })
159 }
160 m.Gen("./combos/marshaler/", []string{
161 "option (gogoproto.unmarshaler_all) = false;",
162 "option (gogoproto.marshaler_all) = true;",
163 })
164 m.Gen("./combos/unmarshaler/", []string{
165 "option (gogoproto.unmarshaler_all) = true;",
166 "option (gogoproto.marshaler_all) = false;",
167 })
168 m.Gen("./combos/both/", []string{
169 "option (gogoproto.unmarshaler_all) = true;",
170 "option (gogoproto.marshaler_all) = true;",
171 })
172 }
173
View as plain text