From 40291a96ddf68d766283850ff11def5823640f7f Mon Sep 17 00:00:00 2001 From: Francesc Campoy Date: Wed, 4 Feb 2015 13:30:07 +0000 Subject: [PATCH] Adding server for code generation --- server/app.yaml | 27 ++++++++++ server/main.go | 19 +++++++ server/server.go | 115 ++++++++++++++++++++++++++++++++++++++++ server/static/home.html | 73 +++++++++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 server/app.yaml create mode 100644 server/main.go create mode 100644 server/server.go create mode 100644 server/static/home.html diff --git a/server/app.yaml b/server/app.yaml new file mode 100644 index 0000000..530472b --- /dev/null +++ b/server/app.yaml @@ -0,0 +1,27 @@ +# Copyright 2015 Google Inc. All rights reserved. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http:#www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to writing, software distributed +# under the License is distributed on a "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. + +# See the License for the specific language governing permissions and +# limitations under the License. + +version: gae +runtime: go +api_version: go1 + +handlers: +- url: /generate + script: _go_app + +- url: / + static_files: static/home.html + upload: static/home.html + +- url: / + static_dir: static diff --git a/server/main.go b/server/main.go new file mode 100644 index 0000000..6207104 --- /dev/null +++ b/server/main.go @@ -0,0 +1,19 @@ +// +build !appengine + +package main + +import ( + "flag" + "net/http" +) + +func main() { + port := flag.String("http", "127.0.0.1:8080", "ip and port to listen to") + flag.Parse() + http.HandleFunc("/", homeHandler) + http.ListenAndServe(*port, nil) +} + +func homeHandler(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, "static/home.html") +} diff --git a/server/server.go b/server/server.go new file mode 100644 index 0000000..4ad8e16 --- /dev/null +++ b/server/server.go @@ -0,0 +1,115 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Server is an http server that provides an alternative way of generating code +// based on int types and the constants defined with it. +// +// Use the http flag to change the address on which the server will listen for +// requests. The default is 127.0.0.1:8080. +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "path/filepath" + "text/template" + + "go/format" + + "github.com/campoy/jsonenums/parser" +) + +func init() { + http.Handle("/generate", handler(generateHandler)) +} + +func generateHandler(w http.ResponseWriter, r *http.Request) error { + if r.Method != "GET" { + return codeError{fmt.Errorf("only GET accepted"), http.StatusMethodNotAllowed} + } + code := r.FormValue("code") + if code == "" { + return codeError{fmt.Errorf("no code to be parsed"), http.StatusBadRequest} + } + typ := r.FormValue("type") + if typ == "" { + return codeError{fmt.Errorf("no type to be analyzed"), http.StatusBadRequest} + } + + dir, err := createDir(code) + if err != nil { + return err + } + defer os.RemoveAll(dir) + + pkg, err := parser.ParsePackage(dir, "") + if err != nil { + return fmt.Errorf("parse package: %v", err) + } + + values, err := pkg.ValuesOfType(typ) + if err != nil { + return fmt.Errorf("find values: %v", err) + } + + t, err := template.New("code").Parse(r.FormValue("template")) + if err != nil { + return codeError{fmt.Errorf("parse template: %v", err), http.StatusBadRequest} + } + var data = struct { + PackageName string + TypeName string + Values []string + }{pkg.Name, typ, values} + + var buf bytes.Buffer + if err := t.Execute(&buf, data); err != nil { + return codeError{fmt.Errorf("execute template: %v", err), http.StatusBadRequest} + } + src, err := format.Source(buf.Bytes()) + if err != nil { + return codeError{fmt.Errorf("code generated is not valid: %v\n%v", err, buf.String()), http.StatusBadRequest} + } + w.Write(src) + return nil +} + +func createDir(content string) (string, error) { + dir, err := ioutil.TempDir("", "jsonenums") + if err != nil { + return "", fmt.Errorf("create tmp dir: %v", err) + } + f, err := os.Create(filepath.Join(dir, "main.go")) + if err != nil { + os.RemoveAll(dir) + return "", fmt.Errorf("create tmp file: %v", err) + } + f.WriteString(content) + f.Close() + return dir, err +} + +type handler func(http.ResponseWriter, *http.Request) error + +func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + err := h(w, r) + if err != nil { + code := http.StatusInternalServerError + if cErr, ok := err.(codeError); ok { + code = cErr.code + } else { + log.Printf("%v: %v", r.URL, code) + } + http.Error(w, err.Error(), code) + } +} + +type codeError struct { + error + code int +} diff --git a/server/static/home.html b/server/static/home.html new file mode 100644 index 0000000..2513053 --- /dev/null +++ b/server/static/home.html @@ -0,0 +1,73 @@ + +jsonenums + + + + + + + +
+ + + +
+ + + + + + +