Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(570)

Side by Side Diff: tools/proto-gae/proto_gae.go

Issue 1625773002: Add tool to generate PropertyConverter implementations for proto messages. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: Fix nit, use bufio Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/proto-gae/README.md ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package main
6
7 import (
8 "bufio"
9 "flag"
10 "fmt"
11 "io"
12 "os"
13 "sort"
14 "strings"
15 "text/template"
16
17 "github.com/luci/luci-go/common/errors"
18 "github.com/luci/luci-go/common/flag/stringsetflag"
19 )
20
21 type app struct {
22 out io.Writer
23
24 packageName string
25 typeNames stringsetflag.Flag
26 outFile string
27 }
28
29 const help = `Usage of %s:
30
31 %s is a go-generator program that generates PropertyConverter implementations
32 for types produced by protoc. It can be used in a go generation file like:
33
34 //go:generate <protoc command>
35 //go:generate proto-gae -type MessageType -type OtherMessageType
36
37 This will produce a new file which implements the ToProperty and FromProperty
38 methods for the named types.
39
40 Options:
41 `
42
43 func (a *app) parseArgs(fs *flag.FlagSet, args []string) error {
44 fs.SetOutput(a.out)
45 fs.Usage = func() {
46 fmt.Fprintf(a.out, help, args[0], args[0])
47 fs.PrintDefaults()
48 }
49
50 fs.Var(&a.typeNames, "type",
51 "A generated proto.Message type to generate stubs for (required, repeatable)")
52 fs.StringVar(&a.outFile, "out", "proto_gae.gen.go",
53 "The name of the output file")
54
55 if err := fs.Parse(args[1:]); err != nil {
56 return err
57 }
58 fail := errors.MultiError(nil)
59 if a.typeNames.Data == nil || a.typeNames.Data.Len() == 0 {
60 fail = append(fail, errors.New("must specify one or more -type") )
61 }
62 if !strings.HasSuffix(a.outFile, ".go") {
63 fail = append(fail, errors.New("-output must end with '.go'"))
64 }
65 if len(fail) > 0 {
66 for _, e := range fail {
67 fmt.Fprintln(a.out, "error:", e)
68 }
69 fmt.Fprintln(a.out)
70 fs.Usage()
71 return fail
72 }
73 return nil
74 }
75
76 var tmpl = template.Must(
77 template.New("main").Parse(`// AUTOGENERATED: Do not edit
78
79 package {{index . "package"}}
80
81 import (
82 "github.com/golang/protobuf/proto"
83
84 "github.com/luci/gae/service/datastore"
85 ){{range index . "types"}}
86
87 var _ datastore.PropertyConverter = (*{{.}})(nil)
88
89 // ToProperty implements datastore.PropertyConverter. It causes an embedded
90 // '{{.}}' to serialize to an unindexed '[]byte' when used with the
91 // "github.com/luci/gae" library.
92 func (p *{{.}}) ToProperty() (prop datastore.Property, err error) {
93 data, err := proto.Marshal(p)
94 if err == nil {
95 prop.SetValue(data, datastore.NoIndex)
96 }
97 return
98 }
99
100 // FromProperty implements datastore.PropertyConverter. It parses a '[]byte'
101 // into an embedded '{{.}}' when used with the "github.com/luci/gae" library.
102 func (p *{{.}}) FromProperty(prop datastore.Property) error {
103 data, err := prop.Project(datastore.PTBytes)
104 if err != nil {
105 return err
106 }
107 return proto.Unmarshal(data.([]byte), p)
108 }{{end}}
109 `))
110
111 func (a *app) writeTo(w io.Writer) error {
112 typeNames := a.typeNames.Data.ToSlice()
113 sort.Strings(typeNames)
114
115 return tmpl.Execute(w, map[string]interface{}{
116 "package": a.packageName,
117 "types": typeNames,
118 })
119 }
120
121 func (a *app) main() {
122 if err := a.parseArgs(flag.NewFlagSet(os.Args[0], flag.ContinueOnError), os.Args); err != nil {
123 os.Exit(1)
124 }
125 ofile, err := os.Create(a.outFile)
126 if err != nil {
127 fmt.Fprintf(a.out, "error: %s", err)
128 os.Exit(2)
129 }
130 closeFn := func(delete bool) {
131 if ofile != nil {
132 if err := ofile.Close(); err != nil {
133 fmt.Fprintf(a.out, "error while closing file: %s ", err)
134 }
135 if delete {
136 if err := os.Remove(a.outFile); err != nil {
137 fmt.Fprintf(a.out, "failed to remove fil e!")
138 }
139 }
140 }
141 ofile = nil
142 }
143 defer closeFn(false)
144 buf := bufio.NewWriter(ofile)
145 err = a.writeTo(buf)
146 if err != nil {
147 fmt.Fprintf(a.out, "error while writing: %s", err)
148 closeFn(true)
149 os.Exit(3)
150 }
151 if err := buf.Flush(); err != nil {
152 fmt.Fprintf(a.out, "error while writing: %s", err)
153 closeFn(true)
154 os.Exit(4)
155 }
156 }
157
158 func main() {
159 (&app{out: os.Stderr, packageName: os.Getenv("GOPACKAGE")}).main()
160 }
OLDNEW
« no previous file with comments | « tools/proto-gae/README.md ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698