From 3627eb2ddcb9f9f58d6c58d12bd5947f618051c0 Mon Sep 17 00:00:00 2001 From: Sergey Lanzman Date: Sat, 23 Jul 2016 21:05:44 +0300 Subject: [PATCH 1/7] refactor generate migration --- g.go | 8 +-- g_migration.go | 157 ++++++++++++++++++++++++++++++++++++++++++++++++- g_scaffold.go | 122 +++----------------------------------- 3 files changed, 166 insertions(+), 121 deletions(-) diff --git a/g.go b/g.go index 3cccfbf..bc4b123 100644 --- a/g.go +++ b/g.go @@ -170,11 +170,9 @@ func generateCode(cmd *Command, args []string) int { upsql := "" downsql := "" if fields != "" { - upsql = `m.SQL("CREATE TABLE ` + mname + "(" + generateSQLFromFields(fields.String()) + `)");` - downsql = `m.SQL("DROP TABLE ` + "`" + mname + "`" + `")` - if driver == "postgres" { - downsql = strings.Replace(downsql, "`", "", -1) - } + dbMigrator := newDBDriver() + upsql = dbMigrator.generateCreateUp(mname) + downsql = dbMigrator.generateCreateDown(mname) } generateMigration(mname, upsql, downsql, currpath) case "controller": diff --git a/g_migration.go b/g_migration.go index 4135ebe..c0485ef 100644 --- a/g_migration.go +++ b/g_migration.go @@ -25,15 +25,168 @@ import ( const ( MPath = "migrations" MDateFormat = "20060102_150405" + DBPath = "database" ) +type DBDriver interface { + generateCreateUp(tableName string) string + generateCreateDown(tableName string) string +} + +type mysqlDriver struct{} + +func (m mysqlDriver) generateCreateUp(tableName string) string { + upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(fields.String()) + `)");` + return upsql +} + +func (m mysqlDriver) generateCreateDown(tableName string) string { + downsql := `m.SQL("DROP TABLE ` + "`" + tableName + "`" + `")` + return downsql +} + +func (m mysqlDriver) generateSQLFromFields(fields string) string { + sql, tags := "", "" + fds := strings.Split(fields, ",") + for i, v := range fds { + kv := strings.SplitN(v, ":", 2) + if len(kv) != 2 { + ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n") + return "" + } + typ, tag := m.getSQLType(kv[1]) + if typ == "" { + ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n") + return "" + } + if i == 0 && strings.ToLower(kv[0]) != "id" { + sql += "`id` int(11) NOT NULL AUTO_INCREMENT," + tags = tags + "PRIMARY KEY (`id`)," + } + sql += "`" + snakeString(kv[0]) + "` " + typ + "," + if tag != "" { + tags = tags + fmt.Sprintf(tag, "`"+snakeString(kv[0])+"`") + "," + } + } + sql = strings.TrimRight(sql+tags, ",") + return sql +} + +func (m mysqlDriver) getSQLType(ktype string) (tp, tag string) { + kv := strings.SplitN(ktype, ":", 2) + switch kv[0] { + case "string": + if len(kv) == 2 { + return "varchar(" + kv[1] + ") NOT NULL", "" + } + return "varchar(128) NOT NULL", "" + case "text": + return "longtext NOT NULL", "" + case "auto": + return "int(11) NOT NULL AUTO_INCREMENT", "" + case "pk": + return "int(11) NOT NULL", "PRIMARY KEY (%s)" + case "datetime": + return "datetime NOT NULL", "" + case "int", "int8", "int16", "int32", "int64": + fallthrough + case "uint", "uint8", "uint16", "uint32", "uint64": + return "int(11) DEFAULT NULL", "" + case "bool": + return "tinyint(1) NOT NULL", "" + case "float32", "float64": + return "float NOT NULL", "" + case "float": + return "float NOT NULL", "" + } + return "", "" +} + +type postgresqlDriver struct{} + +func (m postgresqlDriver) generateCreateUp(tableName string) string { + upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(fields.String()) + `)");` + return upsql +} + +func (m postgresqlDriver) generateCreateDown(tableName string) string { + downsql := `m.SQL("DROP TABLE ` + tableName + `")` + return downsql +} + +func (m postgresqlDriver) generateSQLFromFields(fields string) string { + sql, tags := "", "" + fds := strings.Split(fields, ",") + for i, v := range fds { + kv := strings.SplitN(v, ":", 2) + if len(kv) != 2 { + ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n") + return "" + } + typ, tag := m.getSQLType(kv[1]) + if typ == "" { + ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n") + return "" + } + if i == 0 && strings.ToLower(kv[0]) != "id" { + sql += "id interger serial primary key," + } + sql += snakeString(kv[0]) + " " + typ + "," + if tag != "" { + tags = tags + fmt.Sprintf(tag, snakeString(kv[0])) + "," + } + } + if tags != "" { + sql = strings.TrimRight(sql+" "+tags, ",") + } else { + sql = strings.TrimRight(sql, ",") + } + return sql +} + +func (m postgresqlDriver) getSQLType(ktype string) (tp, tag string) { + kv := strings.SplitN(ktype, ":", 2) + switch kv[0] { + case "string": + if len(kv) == 2 { + return "char(" + kv[1] + ") NOT NULL", "" + } + return "TEXT NOT NULL", "" + case "text": + return "TEXT NOT NULL", "" + case "auto", "pk": + return "serial primary key", "" + case "datetime": + return "TIMESTAMP WITHOUT TIME ZONE NOT NULL", "" + case "int", "int8", "int16", "int32", "int64": + fallthrough + case "uint", "uint8", "uint16", "uint32", "uint64": + return "integer DEFAULT NULL", "" + case "bool": + return "boolean NOT NULL", "" + case "float32", "float64", "float": + return "numeric NOT NULL", "" + } + return "", "" +} + +func newDBDriver() DBDriver { + switch driver { + case "mysql": + return mysqlDriver{} + case "postgres": + return postgresqlDriver{} + default: + panic("driver not supported") + } +} + // generateMigration generates migration file template for database schema update. // The generated file template consists of an up() method for updating schema and // a down() method for reverting the update. func generateMigration(mname, upsql, downsql, curpath string) { w := NewColorWriter(os.Stdout) - - migrationFilePath := path.Join(curpath, "database", MPath) + migrationFilePath := path.Join(curpath, DBPath, MPath) if _, err := os.Stat(migrationFilePath); os.IsNotExist(err) { // create migrations directory if err := os.MkdirAll(migrationFilePath, 0777); err != nil { diff --git a/g_scaffold.go b/g_scaffold.go index 8222b57..cccda16 100644 --- a/g_scaffold.go +++ b/g_scaffold.go @@ -1,9 +1,6 @@ package main -import ( - "fmt" - "strings" -) +import "strings" func generateScaffold(sname, fields, currpath, driver, conn string) { ColorLog("[INFO] Do you want to create a '%v' model? [Yes|No] ", sname) @@ -31,11 +28,13 @@ func generateScaffold(sname, fields, currpath, driver, conn string) { upsql := "" downsql := "" if fields != "" { - upsql = `m.SQL("CREATE TABLE ` + sname + "(" + generateSQLFromFields(fields) + `)");` - downsql = `m.SQL("DROP TABLE ` + "`" + sname + "`" + `")` - if driver == "" { - downsql = strings.Replace(downsql, "`", "", -1) - } + dbMigrator := newDBDriver() + upsql = dbMigrator.generateCreateUp(sname) + downsql = dbMigrator.generateCreateDown(sname) + //todo remove + //if driver == "" { + // downsql = strings.Replace(downsql, "`", "", -1) + //} } generateMigration(sname, upsql, downsql, currpath) } @@ -47,108 +46,3 @@ func generateScaffold(sname, fields, currpath, driver, conn string) { } ColorLog("[INFO] All done! Don't forget to add beego.Router(\"/%v\" ,&controllers.%vController{}) to routers/route.go\n", sname, strings.Title(sname)) } - -func generateSQLFromFields(fields string) string { - sql := "" - tags := "" - fds := strings.Split(fields, ",") - for i, v := range fds { - kv := strings.SplitN(v, ":", 2) - if len(kv) != 2 { - ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n") - return "" - } - typ, tag := "", "" - switch driver { - case "mysql": - typ, tag = getSQLTypeMysql(kv[1]) - case "postgres": - typ, tag = getSQLTypePostgresql(kv[1]) - default: - typ, tag = getSQLTypeMysql(kv[1]) - } - if typ == "" { - ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n") - return "" - } - if i == 0 && strings.ToLower(kv[0]) != "id" { - switch driver { - case "mysql": - sql = sql + "`id` int(11) NOT NULL AUTO_INCREMENT," - tags = tags + "PRIMARY KEY (`id`)," - case "postgres": - sql = sql + "id interger serial primary key," - default: - sql = sql + "`id` int(11) NOT NULL AUTO_INCREMENT," - tags = tags + "PRIMARY KEY (`id`)," - } - } - - sql = sql + "`" + snakeString(kv[0]) + "` " + typ + "," - if tag != "" { - tags = tags + fmt.Sprintf(tag, "`"+snakeString(kv[0])+"`") + "," - } - } - if driver == "postgres" { - sql = strings.Replace(sql, "`", "", -1) - tags = strings.Replace(tags, "`", "", -1) - } - sql = strings.TrimRight(sql+tags, ",") - return sql -} - -func getSQLTypeMysql(ktype string) (tp, tag string) { - kv := strings.SplitN(ktype, ":", 2) - switch kv[0] { - case "string": - if len(kv) == 2 { - return "varchar(" + kv[1] + ") NOT NULL", "" - } - return "varchar(128) NOT NULL", "" - case "text": - return "longtext NOT NULL", "" - case "auto": - return "int(11) NOT NULL AUTO_INCREMENT", "" - case "pk": - return "int(11) NOT NULL", "PRIMARY KEY (%s)" - case "datetime": - return "datetime NOT NULL", "" - case "int", "int8", "int16", "int32", "int64": - fallthrough - case "uint", "uint8", "uint16", "uint32", "uint64": - return "int(11) DEFAULT NULL", "" - case "bool": - return "tinyint(1) NOT NULL", "" - case "float32", "float64": - return "float NOT NULL", "" - case "float": - return "float NOT NULL", "" - } - return "", "" -} - -func getSQLTypePostgresql(ktype string) (tp, tag string) { - kv := strings.SplitN(ktype, ":", 2) - switch kv[0] { - case "string": - if len(kv) == 2 { - return "char(" + kv[1] + ") NOT NULL", "" - } - return "TEXT NOT NULL", "" - case "text": - return "TEXT NOT NULL", "" - case "auto", "pk": - return "serial primary key", "" - case "datetime": - return "TIMESTAMP WITHOUT TIME ZONE NOT NULL", "" - case "int", "int8", "int16", "int32", "int64": - fallthrough - case "uint", "uint8", "uint16", "uint32", "uint64": - return "integer DEFAULT NULL", "" - case "bool": - return "boolean NOT NULL", "" - case "float32", "float64", "float": - return "numeric NOT NULL", "" - } - return "", "" -} From cad9b71bbf09924b5ff821b98443c57ac92ffeda Mon Sep 17 00:00:00 2001 From: astaxie Date: Fri, 19 Aug 2016 22:48:21 +0800 Subject: [PATCH 2/7] hotfix: fix the generate from conn. --- apiapp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiapp.go b/apiapp.go index dda3a22..5a07120 100644 --- a/apiapp.go +++ b/apiapp.go @@ -606,7 +606,7 @@ func createapi(cmd *Command, args []string) int { ColorLog("[INFO] Using '%s' as 'driver'\n", driver) ColorLog("[INFO] Using '%s' as 'conn'\n", conn) ColorLog("[INFO] Using '%s' as 'tables'\n", tables) - generateAppcode(string(driver), string(conn), "3", string(tables), path.Join(apppath, args[0])) + generateAppcode(string(driver), string(conn), "3", string(tables), apppath) } else { os.Mkdir(path.Join(apppath, "models"), 0755) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m") From 340859ea10c1f7e8de1f1aa57e13533ca11b2a4a Mon Sep 17 00:00:00 2001 From: astaxie Date: Fri, 19 Aug 2016 23:00:08 +0800 Subject: [PATCH 3/7] remove docs package --- apiapp.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apiapp.go b/apiapp.go index 5a07120..d76bf34 100644 --- a/apiapp.go +++ b/apiapp.go @@ -69,7 +69,6 @@ EnableDocs = true var apiMaingo = `package main import ( - _ "{{.Appname}}/docs" _ "{{.Appname}}/routers" "github.com/astaxie/beego" @@ -87,7 +86,6 @@ func main() { var apiMainconngo = `package main import ( - _ "{{.Appname}}/docs" _ "{{.Appname}}/routers" "github.com/astaxie/beego" @@ -578,8 +576,6 @@ func createapi(cmd *Command, args []string) int { fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf"), "\x1b[0m") os.Mkdir(path.Join(apppath, "controllers"), 0755) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers"), "\x1b[0m") - os.Mkdir(path.Join(apppath, "docs"), 0755) - fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "docs"), "\x1b[0m") os.Mkdir(path.Join(apppath, "tests"), 0755) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests"), "\x1b[0m") fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m") From 6ccd0e7d9f6d3b5d029d7f0c9975286f623896b6 Mon Sep 17 00:00:00 2001 From: astaxie Date: Fri, 19 Aug 2016 23:31:25 +0800 Subject: [PATCH 4/7] remove bee api default docs --- apiapp.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/apiapp.go b/apiapp.go index d76bf34..d05e0ad 100644 --- a/apiapp.go +++ b/apiapp.go @@ -631,9 +631,6 @@ func createapi(cmd *Command, args []string) int { fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "user.go"), "\x1b[0m") WriteToFile(path.Join(apppath, "models", "user.go"), apiModels2) - fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "docs", "doc.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "docs", "doc.go"), "package docs") - fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m") WriteToFile(path.Join(apppath, "main.go"), strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1)) From 31eaaa14e79638079f5d8fee808aa1bbd4546a7d Mon Sep 17 00:00:00 2001 From: astaxie Date: Fri, 19 Aug 2016 23:31:52 +0800 Subject: [PATCH 5/7] fix: if current path is in GOPATH, create api in current path --- apiapp.go | 10 ++++++++++ new.go | 22 ++++++---------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apiapp.go b/apiapp.go index d05e0ad..f79a7f8 100644 --- a/apiapp.go +++ b/apiapp.go @@ -645,9 +645,19 @@ func checkEnv(appname string) (apppath, packpath string, err error) { ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty") os.Exit(2) } + currpath, _ := os.Getwd() + currpath = path.Join(currpath, appname) + for _, gpath := range gps { + gsrcpath := path.Join(gpath, "src") + if strings.HasPrefix(currpath, gsrcpath) { + return currpath, currpath[len(gsrcpath):], nil + } + } + // In case of multiple paths in the GOPATH, by default // we use the first path gopath := gps[0] + ColorLog("[%s]You current workdir is not a $GOPATH/src, bee will create the application in GOPATH: %s\n", WARN, gopath) Debugf("GOPATH: %s", gopath) gosrcpath := path.Join(gopath, "src") diff --git a/new.go b/new.go index ccdc4f9..e0ba92f 100644 --- a/new.go +++ b/new.go @@ -56,26 +56,16 @@ func init() { func createApp(cmd *Command, args []string) int { ShowShortVersionBanner() - w := NewColorWriter(os.Stdout) - if len(args) != 1 { ColorLog("[ERRO] Argument [appname] is missing\n") os.Exit(2) } - - gps := GetGOPATHs() - if len(gps) == 0 { - ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty") + apppath, packpath, err := checkEnv(args[0]) + if err != nil { + fmt.Println(err) os.Exit(2) } - // In case of multiple paths in the GOPATH, by default - // we use the first path - gopath := gps[0] - Debugf("GOPATH: %s", gopath) - - gosrcpath := path.Join(gopath, "src") // User's workspace - apppath := path.Join(gosrcpath, args[0]) if isExist(apppath) { ColorLog("[ERRO] Path (%s) already exists\n", apppath) @@ -119,13 +109,13 @@ func createApp(cmd *Command, args []string) int { WriteToFile(path.Join(apppath, "views", "index.tpl"), indextpl) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers", "router.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "routers", "router.go"), strings.Replace(router, "{{.Appname}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1)) + WriteToFile(path.Join(apppath, "routers", "router.go"), strings.Replace(router, "{{.Appname}}", packpath, -1)) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests", "default_test.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "tests", "default_test.go"), strings.Replace(test, "{{.Appname}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1)) + WriteToFile(path.Join(apppath, "tests", "default_test.go"), strings.Replace(test, "{{.Appname}}", packpath, -1)) fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m") - WriteToFile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1)) + WriteToFile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", packpath, -1)) ColorLog("[SUCC] New application successfully created!\n") return 0 From b5bf9d07c3d0b345ee0c73f2cb65469368bf9bd4 Mon Sep 17 00:00:00 2001 From: astaxie Date: Fri, 19 Aug 2016 23:45:18 +0800 Subject: [PATCH 6/7] unzip to swagger while not swagger-2 --- apiapp.go | 2 +- rundocs.go | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apiapp.go b/apiapp.go index f79a7f8..4d4e58a 100644 --- a/apiapp.go +++ b/apiapp.go @@ -650,7 +650,7 @@ func checkEnv(appname string) (apppath, packpath string, err error) { for _, gpath := range gps { gsrcpath := path.Join(gpath, "src") if strings.HasPrefix(currpath, gsrcpath) { - return currpath, currpath[len(gsrcpath):], nil + return currpath, currpath[len(gsrcpath)+1:], nil } } diff --git a/rundocs.go b/rundocs.go index 8c840af..35eef7e 100644 --- a/rundocs.go +++ b/rundocs.go @@ -20,6 +20,7 @@ import ( "log" "net/http" "os" + "strings" ) var cmdRundocs = &Command{ @@ -120,6 +121,7 @@ func unzipAndDelete(src string) error { } defer r.Close() + rp := strings.NewReplacer("swagger-"+swaggerVersion, "swagger") for _, f := range r.File { rc, err := f.Open() if err != nil { @@ -127,11 +129,12 @@ func unzipAndDelete(src string) error { } defer rc.Close() + fname := rp.Replace(f.Name) if f.FileInfo().IsDir() { - os.MkdirAll(f.Name, f.Mode()) + os.MkdirAll(fname, f.Mode()) } else { f, err := os.OpenFile( - f.Name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) if err != nil { return err } @@ -143,11 +146,6 @@ func unzipAndDelete(src string) error { } } } - os.RemoveAll("swagger") - err = os.Rename("swagger-"+swaggerVersion, "swagger") - if err != nil { - ColorLog("[%s]Rename swagger-%s to swagger:%s\n", ERRO, swaggerVersion, err) - } ColorLog("[%s]Start delete src file %s\n", INFO, src) return os.RemoveAll(src) } From 5309c72ef751bd4edb45d1702996eb279033b281 Mon Sep 17 00:00:00 2001 From: astaxie Date: Sat, 20 Aug 2016 00:14:39 +0800 Subject: [PATCH 7/7] support success response array objects --- g_docs.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/g_docs.go b/g_docs.go index 3a9b98d..76d11f7 100644 --- a/g_docs.go +++ b/g_docs.go @@ -405,6 +405,23 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat } modelsList[pkgpath+controllerName][st[2]] = mod appendModels(cmpath, pkgpath, controllerName, realTypes) + } else if st[1] == "{array}" { + rs.Schema.Type = "array" + if sType, ok := basicTypes[st[2]]; ok { + typeFormat := strings.Split(sType, ":") + rs.Schema.Type = typeFormat[0] + rs.Schema.Format = typeFormat[1] + } else { + cmpath, m, mod, realTypes := getModel(st[2]) + rs.Schema.Items = &swagger.Propertie{ + Ref: "#/definitions/" + m, + } + if _, ok := modelsList[pkgpath+controllerName]; !ok { + modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema, 0) + } + modelsList[pkgpath+controllerName][st[2]] = mod + appendModels(cmpath, pkgpath, controllerName, realTypes) + } } opts.Responses[st[0]] = rs } else if strings.HasPrefix(t, "@Param") {