diff --git a/codegen.sh b/codegen.sh new file mode 100755 index 000000000..85624d7c0 --- /dev/null +++ b/codegen.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -e +_PWD=$PWD +SPECS=$(find -name 'spec.json' | xargs -n1 dirname) +for SPEC in $SPECS; do + echo "=== spec $SPEC ===" + cd $SPEC && spec && cd $_PWD + + SRC=$(dirname $(dirname $SPEC)) + echo "=== codegen $SRC ===" + cd $SRC && ../codegen/codegen.php && go fmt && cd $_PWD +done \ No newline at end of file diff --git a/crm/_gen.php b/codegen/codegen.php old mode 100644 new mode 100755 similarity index 100% rename from crm/_gen.php rename to codegen/codegen.php diff --git a/crm/templates/http_.tpl b/codegen/templates/http_.tpl similarity index 100% rename from crm/templates/http_.tpl rename to codegen/templates/http_.tpl diff --git a/crm/templates/http_handlers.tpl b/codegen/templates/http_handlers.tpl similarity index 100% rename from crm/templates/http_handlers.tpl rename to codegen/templates/http_handlers.tpl diff --git a/crm/templates/http_interfaces.tpl b/codegen/templates/http_interfaces.tpl similarity index 100% rename from crm/templates/http_interfaces.tpl rename to codegen/templates/http_interfaces.tpl diff --git a/crm/templates/http_request.tpl b/codegen/templates/http_request.tpl similarity index 100% rename from crm/templates/http_request.tpl rename to codegen/templates/http_request.tpl diff --git a/crm/templates/http_routes.tpl b/codegen/templates/http_routes.tpl similarity index 100% rename from crm/templates/http_routes.tpl rename to codegen/templates/http_routes.tpl diff --git a/crm/templates/http_structs.tpl b/codegen/templates/http_structs.tpl similarity index 100% rename from crm/templates/http_structs.tpl rename to codegen/templates/http_structs.tpl diff --git a/crm/templates/warning.tpl b/codegen/templates/warning.tpl similarity index 100% rename from crm/templates/warning.tpl rename to codegen/templates/warning.tpl diff --git a/crm/_gen.sh b/crm/_gen.sh deleted file mode 100755 index 37c7c1cdd..000000000 --- a/crm/_gen.sh +++ /dev/null @@ -1,2 +0,0 @@ -/usr/bin/env php _gen.php -go fmt \ No newline at end of file diff --git a/sam/_gen.php b/sam/_gen.php deleted file mode 100644 index f62a58b4b..000000000 --- a/sam/_gen.php +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env php -set_compile_location("/tmp", true); -$tpl->add_default("newline", "\n"); - -$api_files = glob("docs/src/spec/*.json"); -$apis = array_map(function($filename) { - return array_change_key_case_recursive(json_decode(file_get_contents($filename), true)); -}, $api_files); - -usort($apis, function($a, $b) { - return strcmp($a['interface'], $b['interface']); -}); - -foreach (array("structs", "handlers", "interfaces", "request", "") as $type) { - foreach ($apis as $api) { - if (is_array($api['struct'])) { - $name = ucfirst($api['interface']); - $filename = str_replace("..", ".", strtolower($name) . "." . $type . ".go"); - - $tpl->load("http_$type.tpl"); - $tpl->assign("parsers", array( - "uint64" => "parseUInt64", - "bool" => "parseBool", - )); - $tpl->assign("package", $api['package']); - $tpl->assign("name", $name); - $tpl->assign("self", strtolower(substr($name, 0, 1))); - $tpl->assign("api", $api); - $tpl->assign("structs", $api['struct']); - $imports = array(); - foreach ($api['struct'] as $struct) { - if (isset($struct['imports'])) - foreach ($struct['imports'] as $import) { - $imports[] = $import; - } - } - $tpl->assign("imports", $imports); - $tpl->assign("calls", $api['apis']); - $contents = str_replace("\n\n}", "\n}", $tpl->get()); - - $save = true; - if ($type === "" && file_exists($filename)) { - $save = false; - } - if ($save) { - file_put_contents($filename, $contents); - } - } - } -} - -foreach (array("routes") as $type) { - $name = ucfirst($api['interface']); - $filename = str_replace("..", ".", $type . ".go"); - - $tpl->load("http_$type.tpl"); - $tpl->assign("package", reset($apis)['package']); - $tpl->assign("apis", $apis); - $contents = $tpl->get(); - - file_put_contents($filename, $contents); -} - -// camel case to snake case -function decamel($input) { - preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches); - $ret = $matches[0]; - foreach ($ret as &$match) { - $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match); - } - return implode('_', $ret); -} diff --git a/sam/_gen.sh b/sam/_gen.sh deleted file mode 100755 index 37c7c1cdd..000000000 --- a/sam/_gen.sh +++ /dev/null @@ -1,2 +0,0 @@ -/usr/bin/env php _gen.php -go fmt \ No newline at end of file diff --git a/sam/templates/http_.tpl b/sam/templates/http_.tpl deleted file mode 100644 index ab4bc069f..000000000 --- a/sam/templates/http_.tpl +++ /dev/null @@ -1,14 +0,0 @@ -package {package} - -import ( - "github.com/pkg/errors" -) - -var _ = errors.Wrap - -{foreach $calls as $call} -func (*{name}) {call.name|capitalize}(r *{name|lcfirst}{call.name|capitalize}Request) (interface{}, error) { - return nil, errors.New("Not implemented: {name}.{call.name}") -} - -{/foreach} diff --git a/sam/templates/http_handlers.tpl b/sam/templates/http_handlers.tpl deleted file mode 100644 index 4cb5d854d..000000000 --- a/sam/templates/http_handlers.tpl +++ /dev/null @@ -1,16 +0,0 @@ -package {package} - -{load warning.tpl} - -import ( - "net/http" - - "github.com/titpetric/factory/resputil" -) - -{foreach $calls as $call} -func ({self}h *{name}Handlers) {call.name|capitalize}(w http.ResponseWriter, r *http.Request) { - params := {name|lcfirst}{call.name|capitalize}Request{}.new() - resputil.JSON(w, params.Fill(r), func() (interface{}, error) { return {self}h.{name}.{call.name|capitalize}(params) }) -} -{/foreach} diff --git a/sam/templates/http_interfaces.tpl b/sam/templates/http_interfaces.tpl deleted file mode 100644 index dd0fd91a5..000000000 --- a/sam/templates/http_interfaces.tpl +++ /dev/null @@ -1,39 +0,0 @@ -package {package} - -{load warning.tpl} - -import ( - "net/http" -) - -// HTTP handlers are a superset of internal APIs -type {name}Handlers struct { - *{name} -} - -func ({name}Handlers) new() *{name}Handlers { - return &{name}Handlers{ - {name}{}.New(), - } -} - -// Internal API interface -type {name}API interface { -{foreach $calls as $call} - {call.name|capitalize}(*{name|lcfirst}{call.name|capitalize}Request) (interface{}, error) -{/foreach} -} - -// HTTP API interface -type {name}HandlersAPI interface { -{foreach $calls as $call} - {call.name|capitalize}(http.ResponseWriter, *http.Request) -{/foreach} - - // Authenticate API requests - Authenticator() func(http.Handler) http.Handler -} - -// Compile time check to see if we implement the interfaces -var _ {name}HandlersAPI = &{name}Handlers{} -var _ {name}API = &{name}{} \ No newline at end of file diff --git a/sam/templates/http_request.tpl b/sam/templates/http_request.tpl deleted file mode 100644 index e0a30ebee..000000000 --- a/sam/templates/http_request.tpl +++ /dev/null @@ -1,51 +0,0 @@ -package {package} - -{load warning.tpl} - -import ( - "net/http" - "github.com/go-chi/chi" -) - -var _ = chi.URLParam - -{foreach $calls as $call} -// {name} {call.name} request parameters -type {name|lcfirst}{call.name|capitalize}Request struct { -{foreach $call.parameters as $params} -{foreach $params as $method => $param} - {param.name} {param.type}{newline} -{/foreach} -{/foreach} -} - -func ({name|lcfirst}{call.name|capitalize}Request) new() *{name|lcfirst}{call.name|capitalize}Request { - return &{name|lcfirst}{call.name|capitalize}Request{} -} - -func ({self} *{name|lcfirst}{call.name|capitalize}Request) Fill(r *http.Request) error { - r.ParseForm() - get := map[string]string{} - post := map[string]string{} - urlQuery := r.URL.Query() - for name, param := range urlQuery { - get[name] = string(param[0]) - } - postVars := r.Form - for name, param := range postVars { - post[name] = string(param[0]) - } -{foreach $call.parameters as $method => $params} -{foreach $params as $param} -{if strtolower($method) === "path"} - {self}.{param.name} = {if ($param.type !== "string")}{$parsers[$param.type]}({/if}chi.URLParam(r, "{param.name}"){if ($param.type !== "string")}){/if}{newline} -{elseif substr($param.type, 0, 2) !== '[]'} - {self}.{param.name} = {if ($param.type !== "string")}{$parsers[$param.type]}({method|strtolower}["{param.name}"]){else}{method|strtolower}["{param.name}"]{/if}{newline} -{/if} -{/foreach} -{/foreach} - return nil -} - -var _ RequestFiller = {name|lcfirst}{call.name|capitalize}Request{}.new() -{/foreach} diff --git a/sam/templates/http_routes.tpl b/sam/templates/http_routes.tpl deleted file mode 100644 index de3447ae6..000000000 --- a/sam/templates/http_routes.tpl +++ /dev/null @@ -1,42 +0,0 @@ -package {package} - -{load warning.tpl} - -import ( - "fmt" - "runtime" - "reflect" - "github.com/go-chi/chi" -) - -func MountRoutes(r chi.Router) { -{foreach $apis as $api} - {api.interface|strtolower} := {api.interface|capitalize}Handlers{}.new() -{/foreach} -{foreach $apis as $api} - r.Group(func (r chi.Router) { - r.Use({api.interface|strtolower}.Authenticator()) - r.Route("{api.path}", func(r chi.Router) { -{foreach $api.apis as $call} - r.{eval echo capitalize(strtolower($call.method))}("{call.path}", {api.interface|strtolower}.{call.name|capitalize}) -{/foreach} - }) - }) -{/foreach} - - var printRoutes func(chi.Routes, string, string) - printRoutes = func(r chi.Routes, indent string, prefix string) { - routes := r.Routes() - for _, route := range routes { - if route.SubRoutes != nil && len(route.SubRoutes.Routes()) > 0 { - fmt.Printf(indent+"%s - with %d handlers, %d subroutes\n", route.Pattern, len(route.Handlers), len(route.SubRoutes.Routes())) - printRoutes(route.SubRoutes, indent+"\t", prefix+route.Pattern[:len(route.Pattern)-2]) - } else { - for key, fn := range route.Handlers { - fmt.Printf("%s%s\t%s -> %s\n", indent, key, prefix+route.Pattern, runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()) - } - } - } - } - printRoutes(r, "", "") -} \ No newline at end of file diff --git a/sam/templates/http_structs.tpl b/sam/templates/http_structs.tpl deleted file mode 100644 index 8b4fd7f9a..000000000 --- a/sam/templates/http_structs.tpl +++ /dev/null @@ -1,58 +0,0 @@ -package {package} - -{load warning.tpl} - -{if !empty($imports)} -import ( -{foreach ($imports as $import)} - "{import}" -{/foreach} -) -{/if} - -type ({foreach $structs as $struct} - -{if strpos($name, "Literal") !== false} - {foreach $struct.fields as $field} - {field}{newline} - {/foreach} -{else} - // {api.title} - {struct.name} struct { -{foreach $struct.fields as $field} - {field.name} {field.type} `{if $field.tag}{$field.tag} {/if}db:"{if $field.dbname}{$field.dbname}{else}{$field.name|decamel}{/if}"`{newline} -{/foreach} - - changed []string - } - -{/if}{/foreach} -) - -/* Constructors */ -{foreach $structs as $struct} -func ({struct.name}) New() *{struct.name} { - return &{struct.name}{} -} -{/foreach} - -/* Getters/setters */ -{foreach $structs as $struct} -{foreach $struct.fields as $field} -func ({self} *{struct.name}) Get{field.name}() {field.type} { - return {self}.{field.name} -} - -func ({self} *{struct.name}) Set{field.name}(value {field.type}) *{struct.name} {{if !$field.complex} - if {self}.{field.name} != value { - {self}.changed = append({self}.changed, "{field.name}") - {self}.{field.name} = value - } -{else} - {self}.{field.name} = value -{/if} - return {self} -} -{/foreach} - -{/foreach} diff --git a/sam/templates/warning.tpl b/sam/templates/warning.tpl deleted file mode 100644 index 87be0f8f1..000000000 --- a/sam/templates/warning.tpl +++ /dev/null @@ -1,14 +0,0 @@ -/* - Hello! This file is auto-generated from `docs/src/spec.json`. - - For development: - In order to update the generated files, edit this file under the location, - add your struct fields, imports, API definitions and whatever you want, and: - - 1. run [spec](https://github.com/titpetric/spec) in the same folder, - 2. run `./_gen.php` in this folder. - - You may edit `{name|strtolower}.go`, `{name|strtolower}.util.go` or `{name|strtolower}_test.go` to - implement your API calls, helper functions and tests. The file `{name|strtolower}.go` - is only generated the first time, and will not be overwritten if it exists. -*/ \ No newline at end of file