Adding server for code generation

This commit is contained in:
Francesc Campoy 2015-02-04 13:30:07 +00:00
parent 62c6805a74
commit 40291a96dd
4 changed files with 234 additions and 0 deletions

27
server/app.yaml Normal file
View File

@ -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

19
server/main.go Normal file
View File

@ -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")
}

115
server/server.go Normal file
View File

@ -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
}

73
server/static/home.html Normal file
View File

@ -0,0 +1,73 @@
<html>
<title>jsonenums</title>
<style>
textarea,
input {
display: block;
width: 80%;
margin: auto;
}
textarea {
height: 200px;
overflow-y: scroll;
}
</style>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script>
function generate() {
$.get("/generate", {
"code": $("#code").val(),
"type": $("#type").val(),
"template": $("#template").val(),
}).done(function(res) {
$("#result").val(res);
$("#result").css('background','#fff');
}).fail(function(res) {
$("#result").val(res.responseText);
$("#result").css('background','#fee');
})
}
</script>
<body>
<form action="/generate" method="GET">
<input type="text" id="type" value="WeekDay">
<textarea id="code">
package test
type WeekDay int
const (
Monday WeekDay = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
</textarea>
<textarea id="template">
package {{.PackageName}}
func (r {{.TypeName}}) String() string {
s, ok := map[{{.TypeName}}]string {
{{range .Values}}{{.}}:"{{.}}",{{end}}
}
if !ok {
return "unknown {{.TypeName}}"
}
return s
}
</textarea>
</form>
<input type="button" onclick="generate()" value="generate code">
<textarea id="result">
</textarea>
</body>
</html>