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

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: 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
« tools/proto-gae/README.md ('K') | « 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 "flag"
9 "fmt"
10 "io"
11 "os"
12 "sort"
13 "strings"
14 "text/template"
15
16 "github.com/luci/luci-go/common/errors"
17 "github.com/luci/luci-go/common/flag/stringsetflag"
18 )
19
20 type app struct {
21 out io.Writer
22
23 packageName string
24 typeNames stringsetflag.Flag
25 outFile string
26 }
27
28 const help = `Usage of %s:
29
30 %s is a go-generator program that generates PropertyConverter implementations
31 for types produced by protoc. It can be used in a go generation file like:
32
33 //go:generate <protoc command>
34 //go:generate proto-gae -type MessageType -type OtherMessageType
35
36 This will produce a new file which implements the ToProperty and FromProperty
37 methods for the named types.
38
39 Options:
40 `
41
42 func (a *app) parseArgs(fs *flag.FlagSet, args []string) error {
43 fs.SetOutput(a.out)
44 fs.Usage = func() {
45 fmt.Fprintf(a.out, help, args[0], args[0])
46 fs.PrintDefaults()
47 }
48
49 fs.Var(&a.typeNames, "type",
50 "A generated proto.Message type to generate stubs for (required, repeatable)")
51 fs.StringVar(&a.outFile, "out", "proto_gae.gen.go",
52 "The name of the output file")
53
54 if err := fs.Parse(args[1:]); err != nil {
55 return err
56 }
57 fail := errors.MultiError(nil)
58 if a.typeNames.Data == nil || a.typeNames.Data.Len() == 0 {
59 fail = append(fail, errors.New("must specify one or more -type") )
60 }
61 if !strings.HasSuffix(a.outFile, ".go") {
62 fail = append(fail, errors.New("-output must end with '.go'"))
63 }
64 if len(fail) > 0 {
65 for _, e := range fail {
66 fmt.Fprintln(a.out, "error:", e)
67 }
68 fmt.Fprintln(a.out)
69 fs.Usage()
70 return fail
71 }
72 return nil
73 }
74
75 var tmpl = template.Must(
76 template.New("main").Parse(`// AUTOGENERATED: Do not edit
77
78 package {{index . "package"}}
79
80 import (
81 "github.com/golang/protobuf/proto"
82
83 "github.com/luci/gae/service/datastore"
84 ){{range index . "types"}}
85
86 var _ datastore.PropertyConverter = (*{{.}})(nil)
87
88 // ToProperty implements datastore.PropertyConverter. It causes an embedded
89 // '{{.}}' to serialize to an unindexed '[]byte' when used with the
90 // "github.com/luci/gae" library.
91 func (p *{{.}}) ToProperty() (prop datastore.Property, err error) {
92 data, err := proto.Marshal(p)
93 if err == nil {
94 prop.SetValue(data, datastore.NoIndex)
95 }
96 return
97 }
98
99 // FromProperty implements datastore.PropertyConverter. It parses a '[]byte'
100 // into an embedded '{{.}}' when used with the "github.com/luci/gae" library.
101 func (p *{{.}}) FromProperty(prop datastore.Property) error {
102 data, err := prop.Project(datastore.PTBytes)
103 if err != nil {
104 return err
105 }
106 return proto.Unmarshal(data.([]byte), p)
107 }{{end}}
108 `))
109
110 func (a *app) writeTo(w io.Writer) error {
111 typeNames := a.typeNames.Data.ToSlice()
112 sort.Strings(typeNames)
113
114 return tmpl.Execute(w, map[string]interface{}{
115 "package": a.packageName,
116 "types": typeNames,
117 })
118 }
119
120 func (a *app) main() {
121 if err := a.parseArgs(flag.NewFlagSet(os.Args[0], flag.ContinueOnError), os.Args); err != nil {
dnj 2016/01/23 06:15:36 nit: Why ContinueOnError instead of ExitOnError?
iannucci 2016/01/23 10:01:07 So that I could theoretically test this, except I
122 os.Exit(1)
123 }
124 ofile, err := os.Create(a.outFile)
125 if err != nil {
126 fmt.Fprintf(a.out, "error: %s", err)
127 os.Exit(2)
128 }
129 defer ofile.Close()
dnj 2016/01/23 06:15:36 I suppose in theory if Close fails this could fail
iannucci 2016/01/23 10:01:07 done, though it's completely overkill.
130 if err := a.writeTo(ofile); err != nil {
131 os.Exit(3)
132 }
133 }
134
135 func main() {
136 (&app{out: os.Stderr, packageName: os.Getenv("GOPACKAGE")}).main()
137 }
OLDNEW
« tools/proto-gae/README.md ('K') | « tools/proto-gae/README.md ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698