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

Side by Side Diff: go/src/infra/gae/epservice/epservice.go

Issue 1153473008: A client/server helper wrapper for endpoints in Go. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: more checks and stuff Created 5 years, 6 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 | « go/src/infra/gae/epclient/epclient.go ('k') | go/src/infra/gae/epservice/example/model.go » ('j') | 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 // EPService will run a local appengine service with all of the endpoint
6 // services under this directory. The tool assumes that:
7 // * goapp exists in PATH (and understands all the import paths in the
8 // defined services)
9 package main
10
11 import (
12 "bytes"
13 "encoding/json"
14 "flag"
15 "fmt"
16 "io/ioutil"
17 "os"
18 "os/exec"
19 "os/signal"
20 "path/filepath"
21 "regexp"
22 "strings"
23 "sync"
24 "text/template"
25 "time"
26
27 "infra/libs/jsutil"
28 )
29
30 var (
31 clearDatastore = flag.Bool("clear_datastore", false, "if set, clear the datastore.")
32 leak = flag.Bool("leak", false, "if set, leak the tempora ry directory.")
33 verbose = flag.Bool("verbose", false, "if set, print skipped packages.")
34 servicePackagesBase = flag.String("base", "infra",
35 "base Go package to walk to find service definitions.")
36 )
37
38 var serviceScript = `{{define "go"}}
39 // DO NOT EDIT
40 // Auto-generated by infra/gae/epservice
41 // {{.Timestamp}}
42
43 package main
44
45 import (
46 "fmt"
47
48 {{range $idx, $pkg := .Pkgs}}
49 pkg{{$idx}} "{{$pkg.Imp}}"{{end}}
50
51 "github.com/GoogleCloudPlatform/go-endpoints/endpoints"
52 )
53
54 func init() {
55 var err error
56 server := endpoints.NewServer("")
57
58 {{range $idx, $pkg := .Pkgs }}
59 err = pkg{{$idx}}.RegisterEndpointsService(server)
60 if err != nil {
61 panic(fmt.Errorf("Error while registering service {{$pkg}}: %s", err))
62 }
63 {{end}}
64
65 server.HandleHTTP(nil)
66 }
67 {{end}}
68 `
69
70 const appYaml = `{{define "yaml"}}
71 # DO NOT EDIT
72 # Auto-generated by infra/gae/epservice
73 # {{.Timestamp}}
74
75 application: epclient-tmp-app
76 version: nope
77 runtime: go
78 api_version: go1
79
80 handlers:
81 - url: /.*
82 script: _go_app
83 {{end}}
84 `
85
86 var templ = template.New("service")
87
88 func init() {
89 template.Must(templ.Parse(serviceScript))
90 template.Must(templ.Parse(appYaml))
91 }
92
93 type templInput struct {
94 Pkgs []Pkg
95 Timestamp time.Time
96 }
97
98 // Pkg holds the import and real filesystem paths of an endpoint service
99 // package. It's exported merely for reflection purposes, since it's used
100 // by text/template.
101 type Pkg struct {
102 Imp string
103 Pth string
104 }
105
106 func boom(err error) {
107 if err != nil {
108 panic(err)
109 }
110 }
111
112 var reRegisterEndpointsService = regexp.MustCompile(
113 `\nfunc RegisterEndpointsService\(\w* \*\w*\.Server\) error {\n`)
dnj 2015/06/09 01:48:14 This seems like a dangerous approach. There are ma
iannucci 2015/06/09 02:22:07 That would be true if we didn't enforce gofmt, but
114
115 func getPkgs() []Pkg {
116 cmd := exec.Command("goapp", "list", "-json", filepath.Join(*servicePack agesBase+"..."))
117 d, err := cmd.Output()
118 boom(err)
119
120 d = []byte("[" + strings.Replace(string(d), "}\n{", "},{", -1) + "]")
121
122 js := interface{}(nil)
123 boom(json.Unmarshal(d, &js))
124
125 ret := []Pkg{}
126
127 type pkgOk struct {
128 p Pkg
129 ok bool
130 }
131 pkgs := make(chan pkgOk)
132 wg := sync.WaitGroup{}
133
134 for _, m := range js.([]interface{}) {
135 pkg := Pkg{
136 jsutil.Get(m, "ImportPath").(string),
137 jsutil.Get(m, "Dir").(string),
138 }
139 wg.Add(1)
140 go func() {
141 defer wg.Done()
142 paths, err := ioutil.ReadDir(pkg.Pth)
143 boom(err)
144
145 for _, f := range paths {
146 if !f.IsDir() && strings.HasSuffix(f.Name(), ".g o") {
147 data, err := ioutil.ReadFile(filepath.Jo in(pkg.Pth, f.Name()))
148 boom(err)
149 if reRegisterEndpointsService.Match(data ) {
150 pkgs <- pkgOk{pkg, true}
151 return
152 }
153 }
154 }
155 pkgs <- pkgOk{pkg, false}
156 }()
157 }
158 go func() {
159 wg.Wait()
160 close(pkgs)
161 }()
162
163 for p := range pkgs {
164 if !p.ok {
165 if *verbose {
166 fmt.Println("skipping package", p.p.Imp, "(it do esn't impliment RegisterEndpointsService?)")
167 }
168 } else {
169 fmt.Println("including package", p.p.Imp)
170 ret = append(ret, p.p)
171 }
172 }
173
174 return ret
175 }
176
177 func writeFiles(dir string, pkgs []Pkg) {
178 input := &templInput{pkgs, time.Now()}
179 for _, ext := range []string{"go", "yaml"} {
180 buf := &bytes.Buffer{}
181 boom(templ.ExecuteTemplate(buf, ext, input))
182 boom(ioutil.WriteFile(filepath.Join(dir, "app."+ext), buf.Bytes( ), 0666))
183 }
184 }
185
186 func startServer(dir string) (func(), func()) {
187 args := []string{"serve"}
188 if *clearDatastore {
189 args = append(args, "-clear_datastore")
190 }
191 args = append(args, dir)
192 server := exec.Command("goapp", args...)
193 server.Stdout = os.Stdout
194 server.Stderr = os.Stderr
195 boom(server.Start())
196
197 wait := func() { server.Wait() }
198 stop := func() {
199 server.Process.Signal(os.Interrupt)
200 wait()
201 }
202 return stop, wait
203 }
204
205 func main() {
206 _, err := exec.LookPath("goapp")
207 if err != nil {
208 panic("goapp must be on your path")
209 }
210
211 flag.Parse()
212 pkgs := getPkgs()
213
214 dir, err := ioutil.TempDir("", "epservice_gen")
215 boom(err)
216 prefix := "LEAKING"
217 if !*leak {
218 prefix = "generating"
219 defer os.RemoveAll(dir)
220 }
221 fmt.Println(prefix, "files in:", dir)
222
223 writeFiles(dir, pkgs)
224
225 stop, wait := startServer(dir)
226 intChan := make(chan os.Signal, 1)
227 signal.Notify(intChan, os.Interrupt, os.Kill)
228 go func() {
229 <-intChan
230 stop()
dnj 2015/06/09 01:48:13 Since you are not exiting on signal, "stop()" can
iannucci 2015/06/09 02:22:07 Done.
231 }()
232 defer stop()
233 wait()
234 }
OLDNEW
« no previous file with comments | « go/src/infra/gae/epclient/epclient.go ('k') | go/src/infra/gae/epservice/example/model.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698