Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 // The following comment allows `go generate` to correctly generate clients | |
| 6 // for all endpoints services located in the "infra/gae/epservice" package. | |
| 7 //go:generate goapp run epclient.go | |
| 8 | |
| 9 // EPClient will auto-generate endpoints clients from Google Cloud Endpoint | |
| 10 // service definitions. The tool assumes that: | |
| 11 // * all go endpoint service definitions occur in a package which has | |
| 12 // a public method `RegisterEndpointsService(*endpoints.Server) error`, and | |
| 13 // that calling this method will register the endpoints service with the | |
| 14 // provided server or return an error. | |
| 15 // * goapp exists in PATH (and understands all the import paths in the | |
| 16 // defined services) | |
| 17 // * google-api-go-generator exists in PATH. | |
|
dnj
2015/06/08 16:43:18
Could you "enforce" this by adding it as a Go depe
iannucci
2015/06/09 00:01:54
It's a 'main' package, so I can't add it as an imp
| |
| 18 package main | |
| 19 | |
| 20 import ( | |
| 21 "bytes" | |
| 22 "encoding/json" | |
| 23 "flag" | |
| 24 "fmt" | |
| 25 "io/ioutil" | |
| 26 "os" | |
| 27 "os/exec" | |
| 28 "path/filepath" | |
| 29 "strings" | |
| 30 "text/template" | |
| 31 "time" | |
| 32 | |
| 33 "infra/libs/jsutil" | |
| 34 ) | |
| 35 | |
| 36 var ( | |
| 37 servicePackagesBase = flag.String("pkgs", "infra/gae/epservice", | |
| 38 "The base Go package to walk to find service definitions.") | |
| 39 outDir = flag.String("outdir", ".", | |
| 40 "The directory to generate the client libraries in.") | |
| 41 runOnly = flag.Bool("run", false, | |
| 42 "If set to true, will run the server and wait, without generatin g any clients.") | |
| 43 clearDatastore = flag.Bool("clear_datastore", false, | |
| 44 "If set to true, will clear the datastore when in 'run' mode.") | |
| 45 ) | |
| 46 | |
| 47 var serviceScript = ` | |
| 48 package main | |
|
dnj
2015/06/08 16:43:18
Add "generated" comment, info, timestamp.
iannucci
2015/06/09 00:01:54
Done.
| |
| 49 | |
| 50 import ( | |
| 51 "fmt" | |
| 52 | |
| 53 {{range $idx, $pkg := .Pkgs}} | |
| 54 pkg{{$idx}} "{{$pkg.Imp}}"{{end}} | |
| 55 | |
| 56 "github.com/GoogleCloudPlatform/go-endpoints/endpoints" | |
| 57 ) | |
| 58 | |
| 59 func init() { | |
| 60 var err error | |
| 61 server := endpoints.NewServer("") | |
| 62 | |
| 63 {{range $idx, $pkg := .Pkgs }} | |
| 64 err = pkg{{$idx}}.RegisterEndpointsService(server) | |
| 65 if err != nil { | |
| 66 panic(fmt.Errorf("Error while registering service {{$pkg}}: %s", err)) | |
| 67 } | |
| 68 {{end}} | |
| 69 | |
| 70 server.HandleHTTP(nil) | |
| 71 } | |
| 72 ` | |
| 73 | |
| 74 const appYaml = ` | |
| 75 application: epclient-tmp-app | |
|
dnj
2015/06/08 16:43:18
Add "generated" comment, info, timestamp.
iannucci
2015/06/09 00:01:54
Done.
| |
| 76 version: nope | |
| 77 runtime: go | |
| 78 api_version: go1 | |
| 79 | |
| 80 handlers: | |
| 81 - url: /.* | |
| 82 script: _go_app | |
| 83 ` | |
| 84 | |
| 85 var temp = template.Must(template.New("service").Parse(serviceScript)) | |
| 86 | |
| 87 // Pkg holds the import and real filesystem paths of an endpoint service | |
| 88 // package. It's exported merely for reflection purposes, since it's used | |
| 89 // by text/template. | |
| 90 type Pkg struct { | |
| 91 Imp string | |
| 92 Pth string | |
| 93 } | |
| 94 | |
| 95 func boom(err error) { | |
| 96 if err != nil { | |
| 97 panic(err) | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 func getPkgs() []Pkg { | |
| 102 cmd := exec.Command("goapp", "list", "-json", filepath.Join(*servicePack agesBase, "...")) | |
| 103 d, err := cmd.Output() | |
| 104 boom(err) | |
| 105 | |
| 106 d = []byte("[" + strings.Replace(string(d), "}\n{", "},{", -1) + "]") | |
| 107 | |
| 108 js := interface{}(nil) | |
| 109 boom(json.Unmarshal(d, &js)) | |
| 110 | |
| 111 ret := []Pkg{} | |
| 112 | |
| 113 for _, m := range js.([]interface{}) { | |
| 114 ret = append(ret, Pkg{ | |
| 115 jsutil.Get(m, "ImportPath").(string), | |
| 116 jsutil.Get(m, "Dir").(string), | |
| 117 }) | |
| 118 } | |
| 119 | |
| 120 return ret | |
| 121 } | |
| 122 | |
| 123 func writeFiles(dir string, pkgs []Pkg) { | |
| 124 buf := &bytes.Buffer{} | |
| 125 if err := temp.Execute(buf, struct{ Pkgs []Pkg }{pkgs}); err != nil { | |
| 126 panic(err) | |
| 127 } | |
| 128 | |
| 129 if err := ioutil.WriteFile(filepath.Join(dir, "app.go"), buf.Bytes(), 06 66); err != nil { | |
| 130 panic(err) | |
| 131 } | |
| 132 | |
| 133 if err := ioutil.WriteFile(filepath.Join(dir, "app.yaml"), []byte(appYam l), 0666); err != nil { | |
| 134 panic(err) | |
| 135 } | |
| 136 } | |
| 137 | |
| 138 func parseFlags() { | |
| 139 err := error(nil) | |
|
dnj
2015/06/08 16:43:17
I generally prefer "var err error" *shrug* Up to y
iannucci
2015/06/09 00:01:53
me too... I was getting bikeshedding elsewhere on
| |
| 140 flag.Parse() | |
| 141 if *outDir == "" { | |
| 142 if *outDir, err = os.Getwd(); err != nil { | |
| 143 panic(err) | |
| 144 } | |
| 145 } | |
| 146 if *outDir, err = filepath.Abs(*outDir); err != nil { | |
| 147 panic(err) | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 func startServer(dir string) (func(), func()) { | |
| 152 args := []string{"serve"} | |
| 153 if *clearDatastore { | |
| 154 args = append(args, "-clear_datastore") | |
| 155 } | |
| 156 args = append(args, dir) | |
| 157 server := exec.Command("goapp", args...) | |
| 158 server.Stdout = os.Stdout | |
| 159 server.Stderr = os.Stderr | |
| 160 if err := server.Start(); err != nil { | |
| 161 panic(err) | |
| 162 } | |
| 163 time.Sleep(time.Second) // yeah yeah, sue me. | |
|
dnj
2015/06/08 16:43:18
Since you know the discovery service URL, you coul
iannucci
2015/06/09 00:01:54
Done.
| |
| 164 fmt.Println("Discovery service up") | |
| 165 | |
| 166 wait := func() { server.Wait() } | |
| 167 stop := func() { | |
| 168 server.Process.Signal(os.Interrupt) | |
| 169 wait() | |
| 170 } | |
| 171 return stop, wait | |
| 172 } | |
| 173 | |
| 174 func generate() { | |
| 175 gencmd := exec.Command("google-api-go-generator", "-discoveryurl", "http ://localhost:8080/_ah/api/discovery/v1/apis", "-gendir", *outDir, "-cache=false" ) | |
| 176 gencmd.Stdout = os.Stdout | |
| 177 gencmd.Stderr = os.Stderr | |
| 178 if err := gencmd.Run(); err != nil { | |
| 179 panic(err) | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 func main() { | |
| 184 parseFlags() | |
| 185 | |
|
dnj
2015/06/08 16:43:18
Test that "google-api-go-generator" and "goapp" ar
iannucci
2015/06/09 00:01:53
Done.
| |
| 186 pkgs := getPkgs() | |
| 187 | |
| 188 dir, err := ioutil.TempDir("", "epclient_gen") | |
| 189 if err != nil { | |
| 190 panic(err) | |
| 191 } | |
| 192 defer os.RemoveAll(dir) | |
| 193 | |
| 194 writeFiles(dir, pkgs) | |
| 195 | |
| 196 stop, wait := startServer(dir) | |
| 197 defer stop() | |
| 198 | |
| 199 if *runOnly { | |
| 200 wait() | |
| 201 } else { | |
| 202 generate() | |
| 203 } | |
| 204 | |
| 205 // inject DoWithRetries methods. | |
| 206 } | |
| OLD | NEW |