Merge pull request #456 from beego/develop

v1.9.0
This commit is contained in:
astaxie 2017-07-19 00:56:52 +08:00 committed by GitHub
commit aae0cc4587
9 changed files with 200 additions and 60 deletions

View File

@ -29,6 +29,7 @@ import (
_ "github.com/beego/bee/cmd/commands/pack" _ "github.com/beego/bee/cmd/commands/pack"
_ "github.com/beego/bee/cmd/commands/rs" _ "github.com/beego/bee/cmd/commands/rs"
_ "github.com/beego/bee/cmd/commands/run" _ "github.com/beego/bee/cmd/commands/run"
_ "github.com/beego/bee/cmd/commands/server"
_ "github.com/beego/bee/cmd/commands/version" _ "github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/utils" "github.com/beego/bee/utils"
) )

View File

@ -22,7 +22,7 @@ import (
"github.com/beego/bee/config" "github.com/beego/bee/config"
"github.com/beego/bee/generate" "github.com/beego/bee/generate"
"github.com/beego/bee/generate/swaggergen" "github.com/beego/bee/generate/swaggergen"
beeLogger "github.com/beego/bee/logger" "github.com/beego/bee/logger"
"github.com/beego/bee/utils" "github.com/beego/bee/utils"
) )
@ -71,6 +71,7 @@ func init() {
CmdGenerate.Flag.Var(&generate.SQLConn, "conn", "Connection string used by the SQLDriver to connect to a database instance.") CmdGenerate.Flag.Var(&generate.SQLConn, "conn", "Connection string used by the SQLDriver to connect to a database instance.")
CmdGenerate.Flag.Var(&generate.Level, "level", "Either 1, 2 or 3. i.e. 1=models; 2=models and controllers; 3=models, controllers and routers.") CmdGenerate.Flag.Var(&generate.Level, "level", "Either 1, 2 or 3. i.e. 1=models; 2=models and controllers; 3=models, controllers and routers.")
CmdGenerate.Flag.Var(&generate.Fields, "fields", "List of table Fields.") CmdGenerate.Flag.Var(&generate.Fields, "fields", "List of table Fields.")
CmdGenerate.Flag.Var(&generate.DDL, "ddl", "Generate DDL Migration")
commands.AvailableCommands = append(commands.AvailableCommands, CmdGenerate) commands.AvailableCommands = append(commands.AvailableCommands, CmdGenerate)
} }

View File

@ -0,0 +1,76 @@
// Copyright 2013 bee authors
//
// 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 in writing, software
// distributed under the License is distributed on an "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.
package apiapp
import (
"net/http"
beeLogger "github.com/beego/bee/logger"
"os"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/utils"
)
var CmdServer = &commands.Command{
// CustomFlags: true,
UsageLine: "server [port]",
Short: "serving static content over HTTP on port",
Long: `
The command 'server' creates a Beego API application.
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: createAPI,
}
var (
a utils.DocValue
p utils.DocValue
f utils.DocValue
)
func init() {
CmdServer.Flag.Var(&a, "a", "Listen address")
CmdServer.Flag.Var(&p, "p", "Listen port")
CmdServer.Flag.Var(&f, "f", "Static files fold")
commands.AvailableCommands = append(commands.AvailableCommands, CmdServer)
}
func createAPI(cmd *commands.Command, args []string) int {
if len(args) > 0 {
err := cmd.Flag.Parse(args[1:])
if err != nil {
beeLogger.Log.Error(err.Error())
}
}
if a == "" {
a = "127.0.0.1"
}
if p == "" {
p = "8080"
}
if f == "" {
cwd, _ := os.Getwd()
f = utils.DocValue(cwd)
}
beeLogger.Log.Infof("Start server on http://%s:%s, static file %s", a, p, f)
err := http.ListenAndServe(string(a)+":"+string(p), http.FileServer(http.Dir(f)))
if err != nil {
beeLogger.Log.Error(err.Error())
}
return 0
}

View File

@ -57,7 +57,7 @@ Prints the current Bee, Beego and Go version alongside the platform information.
} }
var outputFormat string var outputFormat string
const version = "1.8.4" const version = "1.9.0"
func init() { func init() {
fs := flag.NewFlagSet("version", flag.ContinueOnError) fs := flag.NewFlagSet("version", flag.ContinueOnError)

View File

@ -21,3 +21,4 @@ var SQLConn utils.DocValue
var Level utils.DocValue var Level utils.DocValue
var Tables utils.DocValue var Tables utils.DocValue
var Fields utils.DocValue var Fields utils.DocValue
var DDL utils.DocValue

View File

@ -101,6 +101,7 @@ var typeMappingMysql = map[string]string{
"decimal": "float64", "decimal": "float64",
"binary": "string", // binary "binary": "string", // binary
"varbinary": "string", "varbinary": "string",
"year": "int16",
} }
// typeMappingPostgres maps SQL data type to corresponding Go data type // typeMappingPostgres maps SQL data type to corresponding Go data type
@ -182,6 +183,7 @@ type OrmTag struct {
RelFk bool RelFk bool
ReverseMany bool ReverseMany bool
RelM2M bool RelM2M bool
Comment string //column comment
} }
// String returns the source code string for the Table struct // String returns the source code string for the Table struct
@ -255,6 +257,9 @@ func (tag *OrmTag) String() string {
if len(ormOptions) == 0 { if len(ormOptions) == 0 {
return "" return ""
} }
if tag.Comment != "" {
return fmt.Sprintf("`orm:\"%s\" description:\"%s\"`", strings.Join(ormOptions, ";"), tag.Comment)
}
return fmt.Sprintf("`orm:\"%s\"`", strings.Join(ormOptions, ";")) return fmt.Sprintf("`orm:\"%s\"`", strings.Join(ormOptions, ";"))
} }
@ -298,7 +303,14 @@ func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, ap
defer db.Close() defer db.Close()
if trans, ok := dbDriver[dbms]; ok { if trans, ok := dbDriver[dbms]; ok {
beeLogger.Log.Info("Analyzing database tables...") beeLogger.Log.Info("Analyzing database tables...")
tableNames := trans.GetTableNames(db) var tableNames []string
if len(selectedTableNames) != 0 {
for tableName := range selectedTableNames {
tableNames = append(tableNames, tableName)
}
} else {
tableNames = trans.GetTableNames(db)
}
tables := getTableObjects(tableNames, db, trans) tables := getTableObjects(tableNames, db, trans)
mvcPath := new(MvcPath) mvcPath := new(MvcPath)
mvcPath.ModelPath = path.Join(apppath, "models") mvcPath.ModelPath = path.Join(apppath, "models")
@ -403,7 +415,7 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin
// retrieve columns // retrieve columns
colDefRows, err := db.Query( colDefRows, err := db.Query(
`SELECT `SELECT
column_name, data_type, column_type, is_nullable, column_default, extra column_name, data_type, column_type, is_nullable, column_default, extra, column_comment
FROM FROM
information_schema.columns information_schema.columns
WHERE WHERE
@ -416,12 +428,12 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin
for colDefRows.Next() { for colDefRows.Next() {
// datatype as bytes so that SQL <null> values can be retrieved // datatype as bytes so that SQL <null> values can be retrieved
var colNameBytes, dataTypeBytes, columnTypeBytes, isNullableBytes, columnDefaultBytes, extraBytes []byte var colNameBytes, dataTypeBytes, columnTypeBytes, isNullableBytes, columnDefaultBytes, extraBytes, columnCommentBytes []byte
if err := colDefRows.Scan(&colNameBytes, &dataTypeBytes, &columnTypeBytes, &isNullableBytes, &columnDefaultBytes, &extraBytes); err != nil { if err := colDefRows.Scan(&colNameBytes, &dataTypeBytes, &columnTypeBytes, &isNullableBytes, &columnDefaultBytes, &extraBytes, &columnCommentBytes); err != nil {
beeLogger.Log.Fatal("Could not query INFORMATION_SCHEMA for column information") beeLogger.Log.Fatal("Could not query INFORMATION_SCHEMA for column information")
} }
colName, dataType, columnType, isNullable, columnDefault, extra := colName, dataType, columnType, isNullable, columnDefault, extra, columnComment :=
string(colNameBytes), string(dataTypeBytes), string(columnTypeBytes), string(isNullableBytes), string(columnDefaultBytes), string(extraBytes) string(colNameBytes), string(dataTypeBytes), string(columnTypeBytes), string(isNullableBytes), string(columnDefaultBytes), string(extraBytes), string(columnCommentBytes)
// create a column // create a column
col := new(Column) col := new(Column)
@ -434,6 +446,7 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin
// Tag info // Tag info
tag := new(OrmTag) tag := new(OrmTag)
tag.Column = colName tag.Column = colName
tag.Comment = columnComment
if table.Pk == colName { if table.Pk == colName {
col.Name = "Id" col.Name = "Id"
col.Type = "int" col.Type = "int"

View File

@ -21,7 +21,7 @@ import (
"strings" "strings"
"time" "time"
beeLogger "github.com/beego/bee/logger" "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors" "github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils" "github.com/beego/bee/utils"
) )
@ -203,11 +203,30 @@ func GenerateMigration(mname, upsql, downsql, curpath string) {
fpath := path.Join(migrationFilePath, fmt.Sprintf("%s_%s.go", today, mname)) fpath := path.Join(migrationFilePath, fmt.Sprintf("%s_%s.go", today, mname))
if f, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil { if f, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer utils.CloseFile(f) defer utils.CloseFile(f)
content := strings.Replace(MigrationTPL, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1) ddlSpec := ""
content = strings.Replace(content, "{{CurrTime}}", today, -1) spec := ""
content = strings.Replace(content, "{{UpSQL}}", upsql, -1) up := ""
content = strings.Replace(content, "{{DownSQL}}", downsql, -1) down := ""
f.WriteString(content) if DDL != "" {
ddlSpec = "m.ddlSpec()"
switch strings.Title(DDL.String()) {
case "Create":
spec = strings.Replace(DDLSpecCreate, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1)
case "Alter":
spec = strings.Replace(DDLSpecAlter, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1)
}
spec = strings.Replace(spec, "{{tableName}}", mname, -1)
} else {
up = strings.Replace(MigrationUp, "{{UpSQL}}", upsql, -1)
up = strings.Replace(up, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1)
down = strings.Replace(MigrationDown, "{{DownSQL}}", downsql, -1)
down = strings.Replace(down, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1)
}
header := strings.Replace(MigrationHeader, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1)
header = strings.Replace(header, "{{ddlSpec}}", ddlSpec, -1)
header = strings.Replace(header, "{{CurrTime}}", today, -1)
f.WriteString(header + spec + up + down)
// Run 'gofmt' on the generated source code // Run 'gofmt' on the generated source code
utils.FormatSourceCode(fpath) utils.FormatSourceCode(fpath)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m") fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
@ -216,33 +235,56 @@ func GenerateMigration(mname, upsql, downsql, curpath string) {
} }
} }
const MigrationTPL = `package main const (
MigrationHeader = `package main
import (
"github.com/astaxie/beego/migration"
)
import ( // DO NOT MODIFY
"github.com/astaxie/beego/migration" type {{StructName}} struct {
migration.Migration
}
// DO NOT MODIFY
func init() {
m := &{{StructName}}{}
m.Created = "{{CurrTime}}"
{{ddlSpec}}
migration.Register("{{StructName}}", m)
}
`
DDLSpecCreate = `
/*
refer beego/migration/doc.go
*/
func(m *{{StructName}}) ddlSpec(){
m.CreateTable("{{tableName}}", "InnoDB", "utf8")
m.PriCol("id").SetAuto(true).SetNullable(false).SetDataType("INT(10)").SetUnsigned(true)
}
`
DDLSpecAlter = `
/*
refer beego/migration/doc.go
*/
func(m *{{StructName}}) ddlSpec(){
m.AlterTable("{{tableName}}")
}
`
MigrationUp = `
// Run the migrations
func (m *{{StructName}}) Up() {
// use m.SQL("CREATE TABLE ...") to make schema update
{{UpSQL}}
}`
MigrationDown = `
// Reverse the migrations
func (m *{{StructName}}) Down() {
// use m.SQL("DROP TABLE ...") to reverse schema update
{{DownSQL}}
}
`
) )
// DO NOT MODIFY
type {{StructName}} struct {
migration.Migration
}
// DO NOT MODIFY
func init() {
m := &{{StructName}}{}
m.Created = "{{CurrTime}}"
migration.Register("{{StructName}}", m)
}
// Run the migrations
func (m *{{StructName}}) Up() {
// use m.SQL("CREATE TABLE ...") to make schema update
{{UpSQL}}
}
// Reverse the migrations
func (m *{{StructName}}) Down() {
// use m.SQL("DROP TABLE ...") to reverse schema update
{{DownSQL}}
}
`

View File

@ -167,7 +167,7 @@ func Add{{modelName}}(m *{{modelName}}) (id int64, err error) {
func Get{{modelName}}ById(id int64) (v *{{modelName}}, err error) { func Get{{modelName}}ById(id int64) (v *{{modelName}}, err error) {
o := orm.NewOrm() o := orm.NewOrm()
v = &{{modelName}}{Id: id} v = &{{modelName}}{Id: id}
if err = o.Read(v); err == nil { if err = o.QueryTable(new({{modelName}})).Filter("Id", id).RelatedSel().One(v); err == nil {
return v, nil return v, nil
} }
return nil, err return nil, err
@ -225,7 +225,7 @@ func GetAll{{modelName}}(query map[string]string, fields []string, sortby []stri
} }
var l []{{modelName}} var l []{{modelName}}
qs = qs.OrderBy(sortFields...) qs = qs.OrderBy(sortFields...).RelatedSel()
if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil { if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
if len(fields) == 0 { if len(fields) == 0 {
for _, v := range l { for _, v := range l {

View File

@ -104,7 +104,11 @@ func ParsePackagesFromDir(dirpath string) {
return nil return nil
} }
if !strings.Contains(fpath, "vendor") && !strings.Contains(fpath, "tests") { // 7 is length of 'vendor' (6) + length of file path separator (1)
// so we skip dir 'vendor' which is directly under dirpath
if !(len(fpath) == len(dirpath)+7 && strings.HasSuffix(fpath, "vendor")) &&
!strings.Contains(fpath, "tests") &&
!(len(fpath) > len(dirpath) && fpath[len(dirpath)+1] == '.') {
err = parsePackageFromDir(fpath) err = parsePackageFromDir(fpath)
if err != nil { if err != nil {
// Send the error to through the channel and continue walking // Send the error to through the channel and continue walking
@ -707,21 +711,23 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
controllerList[pkgpath+controllerName] = make(map[string]*swagger.Item) controllerList[pkgpath+controllerName] = make(map[string]*swagger.Item)
item = &swagger.Item{} item = &swagger.Item{}
} }
switch HTTPMethod { for _, hm := range strings.Split(HTTPMethod, ",") {
case "GET": switch hm {
item.Get = &opts case "GET":
case "POST": item.Get = &opts
item.Post = &opts case "POST":
case "PUT": item.Post = &opts
item.Put = &opts case "PUT":
case "PATCH": item.Put = &opts
item.Patch = &opts case "PATCH":
case "DELETE": item.Patch = &opts
item.Delete = &opts case "DELETE":
case "HEAD": item.Delete = &opts
item.Head = &opts case "HEAD":
case "OPTIONS": item.Head = &opts
item.Options = &opts case "OPTIONS":
item.Options = &opts
}
} }
controllerList[pkgpath+controllerName][routerPath] = item controllerList[pkgpath+controllerName][routerPath] = item
} }