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

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: rm newline 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
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 // NOTE: if you format your RegisterEndpointsService implementation like a bozo,
113 // then this won't match. Don't do that.
114 var reRegisterEndpointsService = regexp.MustCompile(
115 `\nfunc RegisterEndpointsService\(\w* \*\w*\.Server\) error {\n`)
116
117 func getPkgs() []Pkg {
118 cmd := exec.Command("goapp", "list", "-json", filepath.Join(*servicePack agesBase+"..."))
119 d, err := cmd.Output()
120 boom(err)
121
122 d = []byte("[" + strings.Replace(string(d), "}\n{", "},{", -1) + "]")
123
124 js := interface{}(nil)
125 boom(json.Unmarshal(d, &js))
126
127 ret := []Pkg{}
128
129 type pkgOk struct {
130 p Pkg
131 ok bool
132 }
133 pkgs := make(chan pkgOk)
134 wg := sync.WaitGroup{}
135
136 for _, m := range js.([]interface{}) {
137 pkg := Pkg{
138 jsutil.Get(m, "ImportPath").(string),
139 jsutil.Get(m, "Dir").(string),
140 }
141 wg.Add(1)
142 go func() {
143 defer wg.Done()
144 paths, err := ioutil.ReadDir(pkg.Pth)
145 boom(err)
146
147 for _, f := range paths {
148 if !f.IsDir() && strings.HasSuffix(f.Name(), ".g o") {
149 data, err := ioutil.ReadFile(filepath.Jo in(pkg.Pth, f.Name()))
150 boom(err)
151 if reRegisterEndpointsService.Match(data ) {
152 pkgs <- pkgOk{pkg, true}
153 return
154 }
155 }
156 }
157 pkgs <- pkgOk{pkg, false}
158 }()
159 }
160 go func() {
161 wg.Wait()
162 close(pkgs)
163 }()
164
165 for p := range pkgs {
166 if !p.ok {
167 if *verbose {
168 fmt.Println("skipping package", p.p.Imp, "(it do esn't impliment RegisterEndpointsService?)")
169 }
170 } else {
171 fmt.Println("including package", p.p.Imp)
172 ret = append(ret, p.p)
173 }
174 }
175
176 return ret
177 }
178
179 func writeFiles(dir string, pkgs []Pkg) {
180 input := &templInput{pkgs, time.Now()}
181 for _, ext := range []string{"go", "yaml"} {
182 buf := &bytes.Buffer{}
183 boom(templ.ExecuteTemplate(buf, ext, input))
184 boom(ioutil.WriteFile(filepath.Join(dir, "app."+ext), buf.Bytes( ), 0666))
185 }
186 }
187
188 func startServer(dir string) func() {
189 args := []string{"serve"}
190 if *clearDatastore {
191 args = append(args, "-clear_datastore")
192 }
193 args = append(args, dir)
194 server := exec.Command("goapp", args...)
195 server.SysProcAttr = serverStartParams
196 server.Stdout = os.Stdout
197 server.Stderr = os.Stderr
198 boom(server.Start())
199
200 return func() {
201 server.Process.Signal(os.Interrupt)
202 server.Wait()
203 }
204 }
205
206 func main() {
207 _, err := exec.LookPath("goapp")
208 if err != nil {
209 panic("goapp must be on your path")
210 }
211
212 flag.Parse()
213 pkgs := getPkgs()
214
215 dir, err := ioutil.TempDir("", "epservice_gen")
216 boom(err)
217 prefix := "LEAKING"
218 if !*leak {
219 prefix = "generating"
220 defer os.RemoveAll(dir)
221 }
222 fmt.Println(prefix, "files in:", dir)
223
224 writeFiles(dir, pkgs)
225
226 intC := make(chan os.Signal, 1)
227 signal.Notify(intC, os.Interrupt, os.Kill)
228
229 stop := startServer(dir)
230 defer stop()
231 <-intC
232 }
OLDNEW
« no previous file with comments | « go/src/infra/gae/epclient/epclient.infra_testing ('k') | go/src/infra/gae/epservice/epservice.infra_testing » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698