Skip to content

Commit

Permalink
Works for creating go-kit#70 example.
Browse files Browse the repository at this point in the history
  • Loading branch information
kujtimiihoxha committed Apr 10, 2017
1 parent e0ae29f commit 814e993
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 18 deletions.
14 changes: 4 additions & 10 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ var initCmd = &cobra.Command{
logrus.Error("You must provide the service name")
return
}
if viper.GetString("gk_transport") == "" {
viper.Set("gk_transport", viper.GetString("default_transport"))
}
gen := generator.NewServiceInitGenerator()
err := gen.Generate(args[0])
if err != nil {
Expand All @@ -27,16 +30,7 @@ var initCmd = &cobra.Command{

func init() {
RootCmd.AddCommand(initCmd)

// Here you will define your flags and configuration settings.

// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// initCmd.PersistentFlags().String("foo", "", "A help for foo")

// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
initCmd.Flags().StringP("transport", "t", viper.GetString("default_transport"), "Specify the transport you want to initiate for the service")
initCmd.Flags().StringP("transport", "t", "", "Specify the transport you want to initiate for the service")
viper.BindPFlag("gk_transport", initCmd.Flags().Lookup("transport"))

}
196 changes: 191 additions & 5 deletions generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import (
"github.com/kujtimiihoxha/gk/fs"
"github.com/kujtimiihoxha/gk/parser"
"github.com/kujtimiihoxha/gk/templates"
"github.com/kujtimiihoxha/gk/utils"
"github.com/spf13/viper"
"golang.org/x/tools/imports"
"os"
"strings"
)

var SUPPORTED_TRANSPORTS = []string{"http"}

type ServiceGenerator struct {
}

Expand Down Expand Up @@ -98,6 +102,17 @@ func (sg *ServiceInitGenerator) Generate(name string) error {
if !b {
return errors.New(fmt.Sprintf("Service %s was not found", name))
}
transport := viper.GetString("gk_transport")
supported := false
for _, v := range SUPPORTED_TRANSPORTS {
if v == transport {
supported = true
break
}
}
if !supported {
return errors.New(fmt.Sprintf("Transport `%s` not supported", transport))
}
p := parser.NewFileParser()
s, err := defaultFs.ReadFile(sfile)
if err != nil {
Expand Down Expand Up @@ -129,19 +144,39 @@ func (sg *ServiceInitGenerator) Generate(name string) error {
exists := false
for _, v := range f.Structs {
if v.Name == stub.Name {
logrus.Info(fmt.Sprintf("Service `%s` structure already exists so it will not be recreated.", stub.Name))
logrus.Infof("Service `%s` structure already exists so it will not be recreated.", stub.Name)
exists = true
}
}
if !exists {
s += "\n" + stub.String()
}
exists = false
for _, v := range f.Methods {
if v.Name == "New" {
logrus.Infof("Service `%s` New function already exists so it will not be recreated", stub.Name)
exists = true
}
}
if !exists {
newMethod := parser.NewMethod(
"New",
parser.NamedTypeValue{},
fmt.Sprintf(`s = %s{}
return s`, stub.Name),
[]parser.NamedTypeValue{},
[]parser.NamedTypeValue{
parser.NewNameType("s", stubName),
},
)
s += "\n" + newMethod.String()
}
for _, m := range iface.Methods {
exists = false
m.Struct = parser.NewNameType(strings.ToLower(iface.Name[:2]), "*"+stub.Name)
for _, v := range f.Methods {
if v.Name == m.Name && v.Struct.Type == m.Struct.Type {
logrus.Info(fmt.Sprintf("Service method `%s` already exists so it will not be recreated.", v.Name))
logrus.Infof("Service method `%s` already exists so it will not be recreated.", v.Name)
exists = true
}
}
Expand All @@ -157,13 +192,143 @@ func (sg *ServiceInitGenerator) Generate(name string) error {
if err != nil {
return err
}
err = sg.generateEndpoints(name, iface, sfile)
err = sg.generateEndpoints(name, iface)
if err != nil {
return err
}
err = sg.generateTransport(name, iface, transport)
if err != nil {
return err
}
return nil
}
func (sg *ServiceInitGenerator) generateEndpoints(name string, iface *parser.Interface, serviceFilePath string) error {
func (sg *ServiceInitGenerator) generateTransport(name string, iface *parser.Interface, transport string) error {
switch transport {
case "http":
return sg.generateHttpTransport(name, iface)
default:
return errors.New(fmt.Sprintf("Transport `%s` not supported", transport))
}
}
func (sg *ServiceInitGenerator) generateHttpTransport(name string, iface *parser.Interface) error {
te := template.NewEngine()
defaultFs := fs.Get()
handlerFile := parser.NewFile()
handlerFile.Package = "http"
gosrc := viper.GetString("GOPATH") + "/src/"
gosrc = strings.Replace(gosrc, "\\", "/", -1)
pwd, err := os.Getwd()
if err != nil {
return err
}
if viper.GetString("gk_folder") != "" {
pwd += "/" + viper.GetString("gk_folder")
}
pwd = strings.Replace(pwd, "\\", "/", -1)
projectPath := strings.Replace(pwd, gosrc, "", 1)
enpointsPath, err := te.ExecuteString(viper.GetString("endpoints.path"), map[string]string{
"ServiceName": name,
})
if err != nil {
return err
}
enpointsPath = strings.Replace(enpointsPath, "\\", "/", -1)
endpointsImport := projectPath + "/" + enpointsPath
handlerFile.Imports = []parser.NamedTypeValue{
parser.NewNameType("httptransport", "\"github.com/go-kit/kit/transport/http\""),
parser.NewNameType("", "\""+endpointsImport+"\""),
}

handlerFile.Methods = append(handlerFile.Methods, parser.NewMethod(
"NewHTTPHandler",
parser.NamedTypeValue{},
"m := http.NewServeMux()",
[]parser.NamedTypeValue{
parser.NewNameType("endpoints", "endpoints.Endpoints"),
},
[]parser.NamedTypeValue{
parser.NewNameType("", "http.Handler"),
},
))
for _, m := range iface.Methods {
handlerFile.Methods = append(handlerFile.Methods, parser.NewMethod(
fmt.Sprintf("Decode%sRequest", m.Name),
parser.NamedTypeValue{},
fmt.Sprintf(`req = endpoints.%sRequest{}
err = json.NewDecoder(r.Body).Decode(&r)
return req,err
`, m.Name),
[]parser.NamedTypeValue{
parser.NewNameType("_", "context.Context"),
parser.NewNameType("r", "*http.Request"),
},
[]parser.NamedTypeValue{
parser.NewNameType("req", "interface{}"),
parser.NewNameType("err", "error"),
},
))
handlerFile.Methods = append(handlerFile.Methods, parser.NewMethod(
fmt.Sprintf("Encode%sResponse", m.Name),
parser.NamedTypeValue{},
` w.Header().Set("Content-Type", "application/json; charset=utf-8")
err = json.NewEncoder(w).Encode(response)
json.NewEncoder(w).Encode(response)
return err
`,
[]parser.NamedTypeValue{
parser.NewNameType("_", "context.Context"),
parser.NewNameType("w", "http.ResponseWriter"),
parser.NewNameType("response", "interface{}"),
},
[]parser.NamedTypeValue{
parser.NewNameType("err", "error"),
},
))
handlerFile.Methods[0].Body += "\n" + fmt.Sprintf(`m.Handle("/%s", httptransport.NewServer(
endpoints.%sEndpoint,
Decode%sRequest,
Encode%sResponse,
))`, utils.ToLowerSnakeCase(m.Name), m.Name, m.Name, m.Name)
}
handlerFile.Methods[0].Body += "\n" + "return m"
path, err := te.ExecuteString(viper.GetString("transport.path"), map[string]string{
"ServiceName": name,
"TransportType": "http",
})
if err != nil {
return err
}
b, err := defaultFs.Exists(path)
if err != nil {
return err
}
fname, err := te.ExecuteString(viper.GetString("transport.file_name"), map[string]string{
"ServiceName": name,
"TransportType": "http",
})
if err != nil {
return err
}
tfile := path + defaultFs.FilePathSeparator() + fname
if b {
fex, err := defaultFs.Exists(tfile)
if err != nil {
return err
}
if fex {
logrus.Errorf("Transport for service `%s` exist", name)
logrus.Info("If you are trying to update a service use `gk update service [serviceName]`")
return nil
}
} else {
err = defaultFs.MkdirAll(path)
if err != nil {
return err
}
}
return defaultFs.WriteFile(tfile, handlerFile.String(), false)
}
func (sg *ServiceInitGenerator) generateEndpoints(name string, iface *parser.Interface) error {
te := template.NewEngine()
defaultFs := fs.Get()
enpointsPath, err := te.ExecuteString(viper.GetString("endpoints.path"), map[string]string{
Expand Down Expand Up @@ -204,7 +369,28 @@ func (sg *ServiceInitGenerator) generateEndpoints(name string, iface *parser.Int
file.Structs = []parser.Struct{
parser.NewStruct("Endpoints", []parser.NamedTypeValue{}),
}

gosrc := viper.GetString("GOPATH") + "/src/"
gosrc = strings.Replace(gosrc, "\\", "/", -1)
pwd, err := os.Getwd()
if err != nil {
return err
}
if viper.GetString("gk_folder") != "" {
pwd += "/" + viper.GetString("gk_folder")
}
pwd = strings.Replace(pwd, "\\", "/", -1)
projectPath := strings.Replace(pwd, gosrc, "", 1)
servicePath, err := te.ExecuteString(viper.GetString("service.path"), map[string]string{
"ServiceName": name,
})
if err != nil {
return err
}
servicePath = strings.Replace(servicePath, "\\", "/", -1)
serviceImport := projectPath + "/" + servicePath
file.Imports = []parser.NamedTypeValue{
parser.NewNameType("", "\""+serviceImport+"\""),
}
file.Methods = []parser.Method{
parser.NewMethod(
"New",
Expand Down
4 changes: 2 additions & 2 deletions templates/bindata.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion templates/tmpl/gk.json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"path":"{{`{{toSnakeCase .ServiceName}}`}}{{fileSeparator}}pkg{{fileSeparator}}service",
"file_name":"service.go",
"interface_name":"{{`{{toUpperFirstCamelCase .ServiceName}}`}}Service",
"struct_name":"stub_{{`{{toCamel .ServiceName}}`}}Service"
"struct_name":"stub{{`{{toCamelCase .ServiceName}}`}}Service"
},
"middleware":{
"name":"middleware.go"
Expand Down

0 comments on commit 814e993

Please sign in to comment.