1
0
mirror of https://github.com/beego/bee.git synced 2024-11-22 10:10:53 +00:00

Merge branch 'develop' of https://github.com/beego/bee into develop

This commit is contained in:
astaxie 2016-08-01 14:40:46 +08:00
commit adb346811d
27 changed files with 565 additions and 359 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@
# Folders
_obj
_test
.idea
# Architecture specific extensions/prefixes
*.[568vq]

15
Beefile Normal file
View File

@ -0,0 +1,15 @@
version: 0
gopm:
enable: false
install: false
go_install: false
watch_ext: []
dir_structure:
watch_all: false
controllers: ""
models: ""
others: []
cmd_args: []
envs: []
database:
driver: "mysql"

20
Makefile Normal file
View File

@ -0,0 +1,20 @@
.PHONY: all test clean build install
GOFLAGS ?= $(GOFLAGS:)
all: install test
build:
go build $(GOFLAGS) ./...
install:
go get $(GOFLAGS) ./...
test: install
go test $(GOFLAGS) ./...
bench: install
go test -run=NONE -bench=. $(GOFLAGS) ./...
clean:
go clean $(GOFLAGS) -i ./...

View File

@ -21,7 +21,7 @@ go get github.com/beego/bee
Then you can add `bee` binary to PATH environment variable in your `~/.bashrc` or `~/.bash_profile` file:
```bash
export PATH=$PATH:<your_main_gopath>/bin/bee
export PATH=$PATH:<your_main_gopath>/bin
```
> If you already have `bee` installed, updating `bee` is simple:
@ -199,17 +199,17 @@ usage: bee migrate [Command]
bee migrate [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"]
run all outstanding migrations
-driver: [mysql | postgresql | sqlite], the default is mysql
-driver: [mysql | postgres | sqlite], the default is mysql
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
bee migrate rollback [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"]
rollback the last migration operation
-driver: [mysql | postgresql | sqlite], the default is mysql
-driver: [mysql | postgres | sqlite], the default is mysql
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
bee migrate reset [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"]
rollback all migrations
-driver: [mysql | postgresql | sqlite], the default is mysql
-driver: [mysql | postgres| sqlite], the default is mysql
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
bee migrate refresh [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"]

115
apiapp.go
View File

@ -546,14 +546,17 @@ func init() {
}
func createapi(cmd *Command, args []string) int {
curpath, _ := os.Getwd()
ShowShortVersionBanner()
if len(args) < 1 {
ColorLog("[ERRO] Argument [appname] is missing\n")
os.Exit(2)
}
if len(args) > 1 {
cmd.Flag.Parse(args[1:])
}
apppath, packpath, err := checkEnv(args[0])
if err != nil {
fmt.Println(err)
@ -564,23 +567,25 @@ func createapi(cmd *Command, args []string) int {
}
if conn == "" {
}
os.MkdirAll(apppath, 0755)
fmt.Println("create app folder:", apppath)
os.Mkdir(path.Join(apppath, "conf"), 0755)
fmt.Println("create conf:", path.Join(apppath, "conf"))
os.Mkdir(path.Join(apppath, "controllers"), 0755)
fmt.Println("create controllers:", path.Join(apppath, "controllers"))
os.Mkdir(path.Join(apppath, "docs"), 0755)
fmt.Println("create docs:", path.Join(apppath, "docs"))
os.Mkdir(path.Join(apppath, "tests"), 0755)
fmt.Println("create tests:", path.Join(apppath, "tests"))
fmt.Println("create conf app.conf:", path.Join(apppath, "conf", "app.conf"))
writetofile(path.Join(apppath, "conf", "app.conf"),
strings.Replace(apiconf, "{{.Appname}}", args[0], -1))
ColorLog("[INFO] Creating API...\n")
os.MkdirAll(apppath, 0755)
fmt.Println("\tcreate\t", apppath)
os.Mkdir(path.Join(apppath, "conf"), 0755)
fmt.Println("\tcreate\t", path.Join(apppath, "conf"))
os.Mkdir(path.Join(apppath, "controllers"), 0755)
fmt.Println("\tcreate\t", path.Join(apppath, "controllers"))
os.Mkdir(path.Join(apppath, "docs"), 0755)
fmt.Println("\tcreate\t", path.Join(apppath, "docs"))
os.Mkdir(path.Join(apppath, "tests"), 0755)
fmt.Println("\tcreate\t", path.Join(apppath, "tests"))
fmt.Println("\tcreate\t", path.Join(apppath, "conf", "app.conf"))
WriteToFile(path.Join(apppath, "conf", "app.conf"),
strings.Replace(apiconf, "{{.Appname}}", path.Base(args[0]), -1))
if conn != "" {
fmt.Println("create main.go:", path.Join(apppath, "main.go"))
fmt.Println("\tcreate\t", path.Join(apppath, "main.go"))
maingoContent := strings.Replace(apiMainconngo, "{{.Appname}}", packpath, -1)
maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(driver), -1)
if driver == "mysql" {
@ -588,7 +593,7 @@ func createapi(cmd *Command, args []string) int {
} else if driver == "postgres" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1)
}
writetofile(path.Join(apppath, "main.go"),
WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(
maingoContent,
"{{.conn}}",
@ -599,51 +604,47 @@ 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(curpath, args[0]))
generateAppcode(string(driver), string(conn), "3", string(tables), path.Join(apppath, args[0]))
} else {
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Println("create models:", path.Join(apppath, "models"))
fmt.Println("\tcreate\t", path.Join(apppath, "models"))
os.Mkdir(path.Join(apppath, "routers"), 0755)
fmt.Println(path.Join(apppath, "routers") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "routers") + string(path.Separator))
fmt.Println("create controllers object.go:", path.Join(apppath, "controllers", "object.go"))
writetofile(path.Join(apppath, "controllers", "object.go"),
fmt.Println("\tcreate\t", path.Join(apppath, "controllers", "object.go"))
WriteToFile(path.Join(apppath, "controllers", "object.go"),
strings.Replace(apiControllers, "{{.Appname}}", packpath, -1))
fmt.Println("create controllers user.go:", path.Join(apppath, "controllers", "user.go"))
writetofile(path.Join(apppath, "controllers", "user.go"),
fmt.Println("\tcreate\t", path.Join(apppath, "controllers", "user.go"))
WriteToFile(path.Join(apppath, "controllers", "user.go"),
strings.Replace(apiControllers2, "{{.Appname}}", packpath, -1))
fmt.Println("create tests default.go:", path.Join(apppath, "tests", "default_test.go"))
writetofile(path.Join(apppath, "tests", "default_test.go"),
fmt.Println("\tcreate\t", path.Join(apppath, "tests", "default_test.go"))
WriteToFile(path.Join(apppath, "tests", "default_test.go"),
strings.Replace(apiTests, "{{.Appname}}", packpath, -1))
fmt.Println("create routers router.go:", path.Join(apppath, "routers", "router.go"))
writetofile(path.Join(apppath, "routers", "router.go"),
fmt.Println("\tcreate\t", path.Join(apppath, "routers", "router.go"))
WriteToFile(path.Join(apppath, "routers", "router.go"),
strings.Replace(apirouter, "{{.Appname}}", packpath, -1))
fmt.Println("create models object.go:", path.Join(apppath, "models", "object.go"))
writetofile(path.Join(apppath, "models", "object.go"), apiModels)
fmt.Println("\tcreate\t", path.Join(apppath, "models", "object.go"))
WriteToFile(path.Join(apppath, "models", "object.go"), apiModels)
fmt.Println("create models user.go:", path.Join(apppath, "models", "user.go"))
writetofile(path.Join(apppath, "models", "user.go"), apiModels2)
fmt.Println("\tcreate\t", path.Join(apppath, "models", "user.go"))
WriteToFile(path.Join(apppath, "models", "user.go"), apiModels2)
fmt.Println("create docs doc.go:", path.Join(apppath, "docs", "doc.go"))
writetofile(path.Join(apppath, "docs", "doc.go"), "package docs")
fmt.Println("\tcreate\t", path.Join(apppath, "docs", "doc.go"))
WriteToFile(path.Join(apppath, "docs", "doc.go"), "package docs")
fmt.Println("create main.go:", path.Join(apppath, "main.go"))
writetofile(path.Join(apppath, "main.go"),
fmt.Println("\tcreate\t", path.Join(apppath, "main.go"))
WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1))
}
ColorLog("[SUCC] New API successfully created!\n")
return 0
}
func checkEnv(appname string) (apppath, packpath string, err error) {
curpath, err := os.Getwd()
if err != nil {
return
}
gopath := os.Getenv("GOPATH")
Debugf("gopath:%s", gopath)
if gopath == "" {
@ -651,38 +652,14 @@ func checkEnv(appname string) (apppath, packpath string, err error) {
return
}
appsrcpath := ""
haspath := false
wgopath := path.SplitList(gopath)
for _, wg := range wgopath {
wg = path.Join(wg, "src")
if strings.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) {
haspath = true
appsrcpath = wg
break
}
wg, _ = path.EvalSymlinks(wg)
if strings.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) {
haspath = true
appsrcpath = wg
break
}
}
if !haspath {
err = fmt.Errorf("can't create application outside of GOPATH `%s`\n"+
"you first should `cd $GOPATH%ssrc` then use create\n", gopath, string(path.Separator))
return
}
apppath = path.Join(curpath, appname)
gosrcpath := path.Join(gopath, "src")
apppath = path.Join(gosrcpath, appname)
if _, e := os.Stat(apppath); os.IsNotExist(e) == false {
err = fmt.Errorf("path `%s` exists, can not create app without remove it\n", apppath)
err = fmt.Errorf("Cannot create application without removing `%s` first.", apppath)
ColorLog("[ERRO] Path `%s` already exists\n", apppath)
return
}
packpath = strings.Join(strings.Split(apppath[len(appsrcpath)+1:], string(path.Separator)), "/")
packpath = strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/")
return
}

16
bale.go
View File

@ -46,6 +46,8 @@ func init() {
}
func runBale(cmd *Command, args []string) int {
ShowShortVersionBanner()
err := loadConfig()
if err != nil {
ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
@ -60,13 +62,13 @@ func runBale(cmd *Command, args []string) int {
ColorLog("[WARN] Skipped directory( %s )\n", p)
continue
}
ColorLog("[INFO] Packing directory( %s )\n", p)
ColorLog("[INFO] Packaging directory( %s )\n", p)
filepath.Walk(p, walkFn)
}
// Generate auto-uncompress function.
buf := new(bytes.Buffer)
buf.WriteString(fmt.Sprintf(_BALE_HEADER, conf.Bale.Import,
buf.WriteString(fmt.Sprintf(BaleHeader, conf.Bale.Import,
strings.Join(resFiles, "\",\n\t\t\""),
strings.Join(resFiles, ",\n\t\tbale.R")))
@ -88,7 +90,7 @@ func runBale(cmd *Command, args []string) int {
}
const (
_BALE_HEADER = `package main
BaleHeader = `package main
import(
"os"
@ -176,7 +178,7 @@ func walkFn(resPath string, info os.FileInfo, err error) error {
defer fw.Close()
// Write header.
fmt.Fprintf(fw, _HEADER, resPath)
fmt.Fprintf(fw, Header, resPath)
// Copy and compress data.
gz := gzip.NewWriter(&ByteWriter{Writer: fw})
@ -184,7 +186,7 @@ func walkFn(resPath string, info os.FileInfo, err error) error {
gz.Close()
// Write footer.
fmt.Fprint(fw, _FOOTER)
fmt.Fprint(fw, Footer)
resFiles = append(resFiles, resPath)
return nil
@ -200,7 +202,7 @@ func filterSuffix(name string) bool {
}
const (
_HEADER = `package bale
Header = `package bale
import(
"bytes"
@ -210,7 +212,7 @@ import(
func R%s() []byte {
gz, err := gzip.NewReader(bytes.NewBuffer([]byte{`
_FOOTER = `
Footer = `
}))
if err != nil {

69
banner.go Normal file
View File

@ -0,0 +1,69 @@
package main
import (
"io"
"io/ioutil"
"os"
"runtime"
"text/template"
"time"
)
type vars struct {
GoVersion string
GOOS string
GOARCH string
NumCPU int
GOPATH string
GOROOT string
Compiler string
BeeVersion string
BeegoVersion string
}
func Now(layout string) string {
return time.Now().Format(layout)
}
// Init load the banner and prints it to output
// All errors are ignored, the application will not
// print the banner in case of error.
func InitBanner(out io.Writer, in io.Reader) {
if in == nil {
ColorLog("[ERRO] The input is nil\n")
os.Exit(2)
}
banner, err := ioutil.ReadAll(in)
if err != nil {
ColorLog("[ERRO] Error trying to read the banner\n")
ColorLog("[HINT] %v\n", err)
os.Exit(2)
}
show(out, string(banner))
}
func show(out io.Writer, content string) {
t, err := template.New("banner").
Funcs(template.FuncMap{"Now": Now}).
Parse(content)
if err != nil {
ColorLog("[ERRO] Cannot parse the banner template\n")
ColorLog("[HINT] %v\n", err)
os.Exit(2)
}
t.Execute(out, vars{
runtime.Version(),
runtime.GOOS,
runtime.GOARCH,
runtime.NumCPU(),
os.Getenv("GOPATH"),
runtime.GOROOT(),
runtime.Compiler,
version,
getBeegoVersion(),
})
}

46
conf.go
View File

@ -16,10 +16,13 @@ package main
import (
"encoding/json"
"io/ioutil"
"os"
"gopkg.in/yaml.v2"
)
const CONF_VER = 0
const ConfVer = 0
var defaultConf = `{
"version": 0,
@ -50,20 +53,20 @@ var conf struct {
Install bool
}
// Indicates whether execute "go install" before "go build".
GoInstall bool `json:"go_install"`
WatchExt []string `json:"watch_ext"`
GoInstall bool `json:"go_install" yaml:"go_install"`
WatchExt []string `json:"watch_ext" yaml:"watch_ext"`
DirStruct struct {
WatchAll bool `json:"watch_all"`
WatchAll bool `json:"watch_all" yaml:"watch_all"`
Controllers string
Models string
Others []string // Other directories.
} `json:"dir_structure"`
CmdArgs []string `json:"cmd_args"`
} `json:"dir_structure" yaml:"dir_structure"`
CmdArgs []string `json:"cmd_args" yaml:"cmd_args"`
Envs []string
Bale struct {
Import string
Dirs []string
IngExt []string `json:"ignore_ext"`
IngExt []string `json:"ignore_ext" yaml:"ignore_ext"`
}
Database struct {
Driver string
@ -73,14 +76,9 @@ var conf struct {
// loadConfig loads customized configuration.
func loadConfig() error {
foundConf := false
f, err := os.Open("bee.json")
if err != nil {
// Use default.
err = json.Unmarshal([]byte(defaultConf), &conf)
if err != nil {
return err
}
} else {
if err == nil {
defer f.Close()
ColorLog("[INFO] Detected bee.json\n")
d := json.NewDecoder(f)
@ -88,10 +86,26 @@ func loadConfig() error {
if err != nil {
return err
}
foundConf = true
}
byml, erryml := ioutil.ReadFile("Beefile")
if erryml == nil {
ColorLog("[INFO] Detected Beefile\n")
err = yaml.Unmarshal(byml, &conf)
if err != nil {
return err
}
foundConf = true
}
if !foundConf {
// Use default.
err = json.Unmarshal([]byte(defaultConf), &conf)
if err != nil {
return err
}
}
// Check format version.
if conf.Version != CONF_VER {
if conf.Version != ConfVer {
ColorLog("[WARN] Your bee.json is out-of-date, please update!\n")
ColorLog("[HINT] Compare bee.json under bee source code path and yours\n")
}

11
fix.go
View File

@ -8,6 +8,7 @@ import (
"path/filepath"
"regexp"
"strings"
"fmt"
)
var cmdFix = &Command{
@ -25,9 +26,12 @@ func init() {
}
func runFix(cmd *Command, args []string) int {
ShowShortVersionBanner()
ColorLog("[INFO] Upgrading the application...\n")
dir, err := os.Getwd()
if err != nil {
ColorLog("GetCurrent Path:%s\n", err)
ColorLog("[ERRO] GetCurrent Path:%s\n", err)
}
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
@ -42,13 +46,14 @@ func runFix(cmd *Command, args []string) int {
if strings.HasSuffix(info.Name(), ".exe") {
return nil
}
ColorLog("%s\n", path)
err = fixFile(path)
fmt.Println("\tfix\t", path)
if err != nil {
ColorLog("fixFile:%s\n", err)
ColorLog("[ERRO] Could not fix file: %s\n", err)
}
return err
})
ColorLog("[INFO] Upgrade done!\n")
return 0
}

14
g.go
View File

@ -14,7 +14,10 @@
package main
import "os"
import (
"os"
"strings"
)
var cmdGenerate = &Command{
UsageLine: "generate [Command]",
@ -74,6 +77,8 @@ func init() {
}
func generateCode(cmd *Command, args []string) int {
ShowShortVersionBanner()
curpath, _ := os.Getwd()
if len(args) < 1 {
ColorLog("[ERRO] command is missing\n")
@ -119,7 +124,6 @@ func generateCode(cmd *Command, args []string) int {
os.Exit(2)
}
sname := args[1]
ColorLog("[INFO] Using '%s' as scaffold name\n", sname)
generateScaffold(sname, fields.String(), curpath, driver.String(), conn.String())
case "docs":
generateDocs(curpath)
@ -168,6 +172,9 @@ func generateCode(cmd *Command, args []string) int {
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)
}
}
generateMigration(mname, upsql, downsql, curpath)
case "controller":
@ -192,7 +199,6 @@ func generateCode(cmd *Command, args []string) int {
os.Exit(2)
}
sname := args[1]
ColorLog("[INFO] Using '%s' as model name\n", sname)
generateModel(sname, fields.String(), curpath)
case "view":
if len(args) == 2 {
@ -206,6 +212,6 @@ func generateCode(cmd *Command, args []string) int {
default:
ColorLog("[ERRO] command is missing\n")
}
ColorLog("[SUCC] generate successfully created!\n")
ColorLog("[SUCC] %s successfully generated!\n", strings.Title(gcmd))
return 0
}

View File

@ -29,9 +29,9 @@ import (
)
const (
O_MODEL byte = 1 << iota
O_CONTROLLER
O_ROUTER
OModel byte = 1 << iota
OController
ORouter
)
// DbTransformer has method to reverse engineer a database schema to restful api code
@ -259,11 +259,11 @@ func generateAppcode(driver, connStr, level, tables, currpath string) {
var mode byte
switch level {
case "1":
mode = O_MODEL
mode = OModel
case "2":
mode = O_MODEL | O_CONTROLLER
mode = OModel | OController
case "3":
mode = O_MODEL | O_CONTROLLER | O_ROUTER
mode = OModel | OController | ORouter
default:
ColorLog("[ERRO] Invalid 'level' option: %s\n", level)
ColorLog("[HINT] Level must be either 1, 2 or 3\n")
@ -292,7 +292,7 @@ func generateAppcode(driver, connStr, level, tables, currpath string) {
// Generate takes table, column and foreign key information from database connection
// and generate corresponding golang source files
func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, currpath string) {
func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, apppath string) {
db, err := sql.Open(dbms, connStr)
if err != nil {
ColorLog("[ERRO] Could not connect to %s database: %s, %s\n", dbms, connStr, err)
@ -304,11 +304,11 @@ func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, cu
tableNames := trans.GetTableNames(db)
tables := getTableObjects(tableNames, db, trans)
mvcPath := new(MvcPath)
mvcPath.ModelPath = path.Join(currpath, "models")
mvcPath.ControllerPath = path.Join(currpath, "controllers")
mvcPath.RouterPath = path.Join(currpath, "routers")
mvcPath.ModelPath = path.Join(apppath, "models")
mvcPath.ControllerPath = path.Join(apppath, "controllers")
mvcPath.RouterPath = path.Join(apppath, "routers")
createPaths(mode, mvcPath)
pkgPath := getPackagePath(currpath)
pkgPath := getPackagePath(apppath)
writeSourceFiles(pkgPath, tables, mode, mvcPath, selectedTableNames)
} else {
ColorLog("[ERRO] Generating app code from %s database is not supported yet.\n", dbms)
@ -505,10 +505,9 @@ func (*MysqlDB) GetGoDataType(sqlType string) (goType string) {
typeMapping = typeMappingMysql
if v, ok := typeMapping[sqlType]; ok {
return v
} else {
}
ColorLog("[ERRO] data type (%s) not found!\n", sqlType)
os.Exit(2)
}
return goType
}
@ -692,22 +691,21 @@ func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map
func (*PostgresDB) GetGoDataType(sqlType string) (goType string) {
if v, ok := typeMappingPostgres[sqlType]; ok {
return v
} else {
}
ColorLog("[ERRO] data type (%s) not found!\n", sqlType)
os.Exit(2)
}
return goType
}
// deleteAndRecreatePaths removes several directories completely
func createPaths(mode byte, paths *MvcPath) {
if (mode & O_MODEL) == O_MODEL {
if (mode & OModel) == OModel {
os.Mkdir(paths.ModelPath, 0777)
}
if (mode & O_CONTROLLER) == O_CONTROLLER {
if (mode & OController) == OController {
os.Mkdir(paths.ControllerPath, 0777)
}
if (mode & O_ROUTER) == O_ROUTER {
if (mode & ORouter) == ORouter {
os.Mkdir(paths.RouterPath, 0777)
}
}
@ -716,15 +714,15 @@ func createPaths(mode byte, paths *MvcPath) {
// It will wipe the following directories and recreate them:./models, ./controllers, ./routers
// Newly geneated files will be inside these folders.
func writeSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath, selectedTables map[string]bool) {
if (O_MODEL & mode) == O_MODEL {
if (OModel & mode) == OModel {
ColorLog("[INFO] Creating model files...\n")
writeModelFiles(tables, paths.ModelPath, selectedTables)
}
if (O_CONTROLLER & mode) == O_CONTROLLER {
if (OController & mode) == OController {
ColorLog("[INFO] Creating controller files...\n")
writeControllerFiles(tables, paths.ControllerPath, selectedTables, pkgPath)
}
if (O_ROUTER & mode) == O_ROUTER {
if (ORouter & mode) == ORouter {
ColorLog("[INFO] Creating router files...\n")
writeRouterFile(tables, paths.RouterPath, selectedTables, pkgPath)
}
@ -764,9 +762,9 @@ func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bo
}
template := ""
if tb.Pk == "" {
template = STRUCT_MODEL_TPL
template = StructModelTPL
} else {
template = MODEL_TPL
template = ModelTPL
}
fileStr := strings.Replace(template, "{{modelStruct}}", tb.String(), 1)
fileStr = strings.Replace(fileStr, "{{modelName}}", camelCase(tb.Name), -1)
@ -825,7 +823,7 @@ func writeControllerFiles(tables []*Table, cPath string, selectedTables map[stri
continue
}
}
fileStr := strings.Replace(CTRL_TPL, "{{ctrlName}}", camelCase(tb.Name), -1)
fileStr := strings.Replace(CtrlTPL, "{{ctrlName}}", camelCase(tb.Name), -1)
fileStr = strings.Replace(fileStr, "{{pkgPath}}", pkgPath, -1)
if _, err := f.WriteString(fileStr); err != nil {
ColorLog("[ERRO] Could not write controller file to %s\n", fpath)
@ -851,13 +849,13 @@ func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bo
continue
}
// add name spaces
nameSpace := strings.Replace(NAMESPACE_TPL, "{{nameSpace}}", tb.Name, -1)
nameSpace := strings.Replace(NamespaceTPL, "{{nameSpace}}", tb.Name, -1)
nameSpace = strings.Replace(nameSpace, "{{ctrlName}}", camelCase(tb.Name), -1)
nameSpaces = append(nameSpaces, nameSpace)
}
// add export controller
fpath := path.Join(rPath, "router.go")
routerStr := strings.Replace(ROUTER_TPL, "{{nameSpaces}}", strings.Join(nameSpaces, ""), 1)
routerStr := strings.Replace(RouterTPL, "{{nameSpaces}}", strings.Join(nameSpaces, ""), 1)
routerStr = strings.Replace(routerStr, "{{pkgPath}}", pkgPath, 1)
var f *os.File
var err error
@ -1001,12 +999,12 @@ func getPackagePath(curpath string) (packpath string) {
}
const (
STRUCT_MODEL_TPL = `package models
StructModelTPL = `package models
{{importTimePkg}}
{{modelStruct}}
`
MODEL_TPL = `package models
ModelTPL = `package models
import (
"errors"
@ -1150,7 +1148,7 @@ func Delete{{modelName}}(id int) (err error) {
return
}
`
CTRL_TPL = `package controllers
CtrlTPL = `package controllers
import (
"{{pkgPath}}/models"
@ -1316,7 +1314,7 @@ func (c *{{ctrlName}}Controller) Delete() {
c.ServeJSON()
}
`
ROUTER_TPL = `// @APIVersion 1.0.0
RouterTPL = `// @APIVersion 1.0.0
// @Title beego Test API
// @Description beego has a very cool tools to autogenerate documents for your API
// @Contact astaxie@gmail.com
@ -1338,7 +1336,7 @@ func init() {
beego.AddNamespace(ns)
}
`
NAMESPACE_TPL = `
NamespaceTPL = `
beego.NSNamespace("/{{nameSpace}}",
beego.NSInclude(
&controllers.{{ctrlName}}Controller{},

View File

@ -18,6 +18,7 @@ import (
"os"
"path"
"strings"
"fmt"
)
// article
@ -58,7 +59,7 @@ func generateController(cname, crupath string) {
f.WriteString(content)
// gofmt generated source code
formatSourceCode(fpath)
ColorLog("[INFO] controller file generated: %s\n", fpath)
fmt.Println("\tcreate\t", fpath)
} else {
// error creating file
ColorLog("[ERRO] Could not create controller file: %s\n", err)

View File

@ -332,7 +332,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
if j == 0 || j == 1 {
st[j] = string(tmp)
tmp = make([]rune, 0)
j += 1
j++
start = false
if j == 1 {
continue
@ -594,17 +594,15 @@ func typeAnalyser(f *ast.Field) (isSlice bool, realType string) {
}
if star, ok := arr.Elt.(*ast.StarExpr); ok {
return true, fmt.Sprint(star.X)
} else {
}
return true, fmt.Sprint(arr.Elt)
}
} else {
switch t := f.Type.(type) {
case *ast.StarExpr:
return false, fmt.Sprint(t.X)
}
return false, fmt.Sprint(f.Type)
}
}
func isBasicType(Type string) bool {
for _, v := range basicTypes {
@ -627,7 +625,7 @@ var basicTypes = []string{
}
// regexp get json tag
func grepJsonTag(tag string) string {
func grepJSONTag(tag string) string {
r, _ := regexp.Compile(`json:"([^"]*)"`)
matches := r.FindAllStringSubmatch(tag, -1)
if len(matches) > 0 {

View File

@ -31,11 +31,11 @@ func generateHproseAppcode(driver, connStr, level, tables, currpath string) {
var mode byte
switch level {
case "1":
mode = O_MODEL
mode = OModel
case "2":
mode = O_MODEL | O_CONTROLLER
mode = OModel | OController
case "3":
mode = O_MODEL | O_CONTROLLER | O_ROUTER
mode = OModel | OController | ORouter
default:
ColorLog("[ERRO] Invalid 'level' option: %s\n", level)
ColorLog("[HINT] Level must be either 1, 2 or 3\n")
@ -90,7 +90,7 @@ func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bo
// It will wipe the following directories and recreate them:./models, ./controllers, ./routers
// Newly geneated files will be inside these folders.
func writeHproseSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath, selectedTables map[string]bool) {
if (O_MODEL & mode) == O_MODEL {
if (OModel & mode) == OModel {
ColorLog("[INFO] Creating model files...\n")
writeHproseModelFiles(tables, paths.ModelPath, selectedTables)
}
@ -130,10 +130,10 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str
}
template := ""
if tb.Pk == "" {
template = HPROSE_STRUCT_MODEL_TPL
template = HproseStructModelTPL
} else {
template = HPROSE_MODEL_TPL
hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HPROSE_ADDFUNCTION, "{{modelName}}", camelCase(tb.Name), -1))
template = HproseModelTPL
hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HproseAddFunction, "{{modelName}}", camelCase(tb.Name), -1))
}
fileStr := strings.Replace(template, "{{modelStruct}}", tb.String(), 1)
fileStr = strings.Replace(fileStr, "{{modelName}}", camelCase(tb.Name), -1)
@ -157,7 +157,7 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str
}
const (
HPROSE_ADDFUNCTION = `
HproseAddFunction = `
// publish about {{modelName}} function
service.AddFunction("Add{{modelName}}", models.Add{{modelName}})
service.AddFunction("Get{{modelName}}ById", models.Get{{modelName}}ById)
@ -166,12 +166,12 @@ const (
service.AddFunction("Delete{{modelName}}", models.Delete{{modelName}})
`
HPROSE_STRUCT_MODEL_TPL = `package models
HproseStructModelTPL = `package models
{{importTimePkg}}
{{modelStruct}}
`
HPROSE_MODEL_TPL = `package models
HproseModelTPL = `package models
import (
"errors"

View File

@ -23,15 +23,15 @@ import (
)
const (
M_PATH = "migrations"
M_DATE_FORMAT = "20060102_150405"
MPath = "migrations"
MDateFormat = "20060102_150405"
)
// 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) {
migrationFilePath := path.Join(curpath, "database", M_PATH)
migrationFilePath := path.Join(curpath, "database", MPath)
if _, err := os.Stat(migrationFilePath); os.IsNotExist(err) {
// create migrations directory
if err := os.MkdirAll(migrationFilePath, 0777); err != nil {
@ -40,18 +40,18 @@ func generateMigration(mname, upsql, downsql, curpath string) {
}
}
// create file
today := time.Now().Format(M_DATE_FORMAT)
today := time.Now().Format(MDateFormat)
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 {
defer f.Close()
content := strings.Replace(MIGRATION_TPL, "{{StructName}}", camelCase(mname)+"_"+today, -1)
content := strings.Replace(MigrationTPL, "{{StructName}}", camelCase(mname)+"_"+today, -1)
content = strings.Replace(content, "{{CurrTime}}", today, -1)
content = strings.Replace(content, "{{UpSQL}}", upsql, -1)
content = strings.Replace(content, "{{DownSQL}}", downsql, -1)
f.WriteString(content)
// gofmt generated source code
formatSourceCode(fpath)
ColorLog("[INFO] Migration file generated: %s\n", fpath)
fmt.Println("\tcreate\t", fpath)
} else {
// error creating file
ColorLog("[ERRO] Could not create migration file: %s\n", err)
@ -59,7 +59,7 @@ func generateMigration(mname, upsql, downsql, curpath string) {
}
}
const MIGRATION_TPL = `package main
const MigrationTPL = `package main
import (
"github.com/astaxie/beego/migration"

View File

@ -2,6 +2,7 @@ package main
import (
"errors"
"fmt"
"os"
"path"
"strings"
@ -15,7 +16,7 @@ func generateModel(mname, fields, crupath string) {
i := strings.LastIndex(p[:len(p)-1], "/")
packageName = p[i+1 : len(p)-1]
}
modelStruct, err, hastime := getStruct(modelName, fields)
modelStruct, hastime, err := getStruct(modelName, fields)
if err != nil {
ColorLog("[ERRO] Could not genrate models struct: %s\n", err)
os.Exit(2)
@ -44,7 +45,7 @@ func generateModel(mname, fields, crupath string) {
f.WriteString(content)
// gofmt generated source code
formatSourceCode(fpath)
ColorLog("[INFO] model file generated: %s\n", fpath)
fmt.Println("\tcreate\t", fpath)
} else {
// error creating file
ColorLog("[ERRO] Could not create model file: %s\n", err)
@ -52,9 +53,9 @@ func generateModel(mname, fields, crupath string) {
}
}
func getStruct(structname, fields string) (string, error, bool) {
func getStruct(structname, fields string) (string, bool, error) {
if fields == "" {
return "", errors.New("fields can't empty"), false
return "", false, errors.New("fields can't empty")
}
hastime := false
structStr := "type " + structname + " struct{\n"
@ -62,11 +63,11 @@ func getStruct(structname, fields string) (string, error, bool) {
for i, v := range fds {
kv := strings.SplitN(v, ":", 2)
if len(kv) != 2 {
return "", errors.New("the filds format is wrong. should key:type,key:type " + v), false
return "", false, errors.New("the filds format is wrong. should key:type,key:type " + v)
}
typ, tag, hastimeinner := getType(kv[1])
if typ == "" {
return "", errors.New("the filds format is wrong. should key:type,key:type " + v), false
return "", false, errors.New("the filds format is wrong. should key:type,key:type " + v)
}
if i == 0 && strings.ToLower(kv[0]) != "id" {
structStr = structStr + "Id int64 `orm:\"auto\"`\n"
@ -77,7 +78,7 @@ func getStruct(structname, fields string) (string, error, bool) {
structStr = structStr + camelString(kv[0]) + " " + typ + " " + tag + "\n"
}
structStr += "}\n"
return structStr, nil, hastime
return structStr, hastime, nil
}
// fields support type
@ -88,9 +89,8 @@ func getType(ktype string) (kt, tag string, hasTime bool) {
case "string":
if len(kv) == 2 {
return "string", "`orm:\"size(" + kv[1] + ")\"`", false
} else {
return "string", "`orm:\"size(128)\"`", false
}
return "string", "`orm:\"size(128)\"`", false
case "text":
return "string", "`orm:\"type(longtext)\"`", false
case "auto":

View File

@ -7,34 +7,37 @@ import (
func generateScaffold(sname, fields, crupath, driver, conn string) {
// generate model
ColorLog("[INFO] Do you want me to create a %v model? [yes|no]] ", sname)
ColorLog("[INFO] Do you want to create a %v model? [yes|no]] ", sname)
if askForConfirmation() {
generateModel(sname, fields, crupath)
}
// generate controller
ColorLog("[INFO] Do you want me to create a %v controller? [yes|no]] ", sname)
ColorLog("[INFO] Do you want to create a %v controller? [yes|no]] ", sname)
if askForConfirmation() {
generateController(sname, crupath)
}
// generate view
ColorLog("[INFO] Do you want me to create views for this %v resource? [yes|no]] ", sname)
ColorLog("[INFO] Do you want to create views for this %v resource? [yes|no]] ", sname)
if askForConfirmation() {
generateView(sname, crupath)
}
// generate migration
ColorLog("[INFO] Do you want me to create a %v migration and schema for this resource? [yes|no]] ", sname)
ColorLog("[INFO] Do you want to create a %v migration and schema for this resource? [yes|no]] ", sname)
if askForConfirmation() {
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)
}
}
generateMigration(sname, upsql, downsql, crupath)
}
// run migration
ColorLog("[INFO] Do you want to go ahead and migrate the database? [yes|no]] ")
ColorLog("[INFO] Do you want to migrate the database? [yes|no]] ")
if askForConfirmation() {
migrateUpdate(crupath, driver, conn)
}
@ -48,36 +51,56 @@ func generateSQLFromFields(fields string) string {
for i, v := range fds {
kv := strings.SplitN(v, ":", 2)
if len(kv) != 2 {
ColorLog("[ERRO] the fields format is wrong. should key:type,key:type " + v + "\n")
ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n")
return ""
}
typ, tag := getSqlType(kv[1])
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] the fields format is wrong. should key:type,key:type " + v + "\n")
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 getSqlType(ktype string) (tp, tag string) {
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", ""
} else {
return "varchar(128) NOT NULL", ""
}
return "varchar(128) NOT NULL", ""
case "text":
return "longtext NOT NULL", ""
case "auto":
@ -99,3 +122,29 @@ func getSqlType(ktype string) (tp, tag string) {
}
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 "", ""
}

View File

@ -3,18 +3,20 @@ package main
import (
"os"
"path"
"fmt"
)
// recipe
// admin/recipe
func generateView(vpath, crupath string) {
ColorLog("[INFO] Generating view...\n")
absvpath := path.Join(crupath, "views", vpath)
os.MkdirAll(absvpath, os.ModePerm)
cfile := path.Join(absvpath, "index.tpl")
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer f.Close()
f.WriteString(cfile)
ColorLog("[INFO] Created: %v\n", cfile)
fmt.Println("\tcreate\t", cfile)
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)
@ -23,7 +25,7 @@ func generateView(vpath, crupath string) {
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer f.Close()
f.WriteString(cfile)
ColorLog("[INFO] Created: %v\n", cfile)
fmt.Println("\tcreate\t", cfile)
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)
@ -32,7 +34,7 @@ func generateView(vpath, crupath string) {
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer f.Close()
f.WriteString(cfile)
ColorLog("[INFO] Created: %v\n", cfile)
fmt.Println("\tcreate\t", cfile)
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)
@ -41,7 +43,7 @@ func generateView(vpath, crupath string) {
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer f.Close()
f.WriteString(cfile)
ColorLog("[INFO] Created: %v\n", cfile)
fmt.Println("\tcreate\t", cfile)
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)

View File

@ -255,6 +255,8 @@ func init() {
}
func createhprose(cmd *Command, args []string) int {
ShowShortVersionBanner()
curpath, _ := os.Getwd()
if len(args) > 1 {
cmd.Flag.Parse(args[1:])
@ -269,12 +271,15 @@ func createhprose(cmd *Command, args []string) int {
}
if conn == "" {
}
ColorLog("[INFO] Creating Hprose application...\n")
os.MkdirAll(apppath, 0755)
fmt.Println("create app folder:", apppath)
fmt.Println("\tcreate\t", apppath)
os.Mkdir(path.Join(apppath, "conf"), 0755)
fmt.Println("create conf:", path.Join(apppath, "conf"))
fmt.Println("create conf app.conf:", path.Join(apppath, "conf", "app.conf"))
writetofile(path.Join(apppath, "conf", "app.conf"),
fmt.Println("\tcreate\t", path.Join(apppath, "conf"))
fmt.Println("\tcreate\t", path.Join(apppath, "conf", "app.conf"))
WriteToFile(path.Join(apppath, "conf", "app.conf"),
strings.Replace(hproseconf, "{{.Appname}}", args[0], -1))
if conn != "" {
@ -282,7 +287,7 @@ func createhprose(cmd *Command, args []string) int {
ColorLog("[INFO] Using '%s' as 'conn'\n", conn)
ColorLog("[INFO] Using '%s' as 'tables'\n", tables)
generateHproseAppcode(string(driver), string(conn), "1", string(tables), path.Join(curpath, args[0]))
fmt.Println("create main.go:", path.Join(apppath, "main.go"))
fmt.Println("\tcreate\t", path.Join(apppath, "main.go"))
maingoContent := strings.Replace(hproseMainconngo, "{{.Appname}}", packpath, -1)
maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(driver), -1)
maingoContent = strings.Replace(maingoContent, "{{HproseFunctionList}}", strings.Join(hproseAddFunctions, ""), -1)
@ -291,7 +296,7 @@ func createhprose(cmd *Command, args []string) int {
} else if driver == "postgres" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1)
}
writetofile(path.Join(apppath, "main.go"),
WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(
maingoContent,
"{{.conn}}",
@ -301,17 +306,18 @@ func createhprose(cmd *Command, args []string) int {
)
} else {
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Println("create models:", path.Join(apppath, "models"))
fmt.Println("\tcreate\t", path.Join(apppath, "models"))
fmt.Println("create models object.go:", path.Join(apppath, "models", "object.go"))
writetofile(path.Join(apppath, "models", "object.go"), apiModels)
fmt.Println("\tcreate\t", path.Join(apppath, "models", "object.go"))
WriteToFile(path.Join(apppath, "models", "object.go"), apiModels)
fmt.Println("create models user.go:", path.Join(apppath, "models", "user.go"))
writetofile(path.Join(apppath, "models", "user.go"), apiModels2)
fmt.Println("\tcreate\t", path.Join(apppath, "models", "user.go"))
WriteToFile(path.Join(apppath, "models", "user.go"), apiModels2)
fmt.Println("create main.go:", path.Join(apppath, "main.go"))
writetofile(path.Join(apppath, "main.go"),
fmt.Println("\tcreate\t", path.Join(apppath, "main.go"))
WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(hproseMaingo, "{{.Appname}}", packpath, -1))
}
ColorLog("[SUCC] New Hprose application successfully created!\n")
return 0
}

View File

@ -62,6 +62,8 @@ func init() {
// runMigration is the entry point for starting a migration
func runMigration(cmd *Command, args []string) int {
ShowShortVersionBanner()
crupath, _ := os.Getwd()
gopath := os.Getenv("GOPATH")
@ -165,23 +167,23 @@ func migrate(goal, crupath, driver, connStr string) {
// checkForSchemaUpdateTable checks the existence of migrations table.
// It checks for the proper table structures and creates the table using MYSQL_MIGRATION_DDL if it does not exist.
func checkForSchemaUpdateTable(db *sql.DB, driver string) {
showTableSql := showMigrationsTableSql(driver)
if rows, err := db.Query(showTableSql); err != nil {
showTableSQL := showMigrationsTableSQL(driver)
if rows, err := db.Query(showTableSQL); err != nil {
ColorLog("[ERRO] Could not show migrations table: %s\n", err)
os.Exit(2)
} else if !rows.Next() {
// no migrations table, create anew
createTableSql := createMigrationsTableSql(driver)
createTableSQL := createMigrationsTableSQL(driver)
ColorLog("[INFO] Creating 'migrations' table...\n")
if _, err := db.Query(createTableSql); err != nil {
if _, err := db.Query(createTableSQL); err != nil {
ColorLog("[ERRO] Could not create migrations table: %s\n", err)
os.Exit(2)
}
}
// checking that migrations table schema are expected
selectTableSql := selectMigrationsTableSql(driver)
if rows, err := db.Query(selectTableSql); err != nil {
selectTableSQL := selectMigrationsTableSQL(driver)
if rows, err := db.Query(selectTableSQL); err != nil {
ColorLog("[ERRO] Could not show columns of migrations table: %s\n", err)
os.Exit(2)
} else {
@ -217,7 +219,7 @@ func checkForSchemaUpdateTable(db *sql.DB, driver string) {
}
}
func showMigrationsTableSql(driver string) string {
func showMigrationsTableSQL(driver string) string {
switch driver {
case "mysql":
return "SHOW TABLES LIKE 'migrations'"
@ -228,23 +230,23 @@ func showMigrationsTableSql(driver string) string {
}
}
func createMigrationsTableSql(driver string) string {
func createMigrationsTableSQL(driver string) string {
switch driver {
case "mysql":
return MYSQL_MIGRATION_DDL
return MYSQLMigrationDDL
case "postgres":
return POSTGRES_MIGRATION_DDL
return POSTGRESMigrationDDL
default:
return MYSQL_MIGRATION_DDL
return MYSQLMigrationDDL
}
}
func selectMigrationsTableSql(driver string) string {
func selectMigrationsTableSQL(driver string) string {
switch driver {
case "mysql":
return "DESC migrations"
case "postgres":
return "SELECT * FROM migrations ORDER BY id_migration;"
return "SELECT * FROM migrations WHERE false ORDER BY id_migration;"
default:
return "DESC migrations"
}
@ -288,7 +290,7 @@ func writeMigrationSourceFile(dir, source, driver, connStr string, latestTime in
ColorLog("[ERRO] Could not create file: %s\n", err)
os.Exit(2)
} else {
content := strings.Replace(MIGRATION_MAIN_TPL, "{{DBDriver}}", driver, -1)
content := strings.Replace(MigrationMainTPL, "{{DBDriver}}", driver, -1)
content = strings.Replace(content, "{{ConnStr}}", connStr, -1)
content = strings.Replace(content, "{{LatestTime}}", strconv.FormatInt(latestTime, 10), -1)
content = strings.Replace(content, "{{LatestName}}", latestName, -1)
@ -367,7 +369,7 @@ func formatShellOutput(o string) {
}
const (
MIGRATION_MAIN_TPL = `package main
MigrationMainTPL = `package main
import(
"os"
@ -406,7 +408,7 @@ func main(){
}
`
MYSQL_MIGRATION_DDL = `
MYSQLMigrationDDL = `
CREATE TABLE migrations (
id_migration int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'surrogate key',
name varchar(255) DEFAULT NULL COMMENT 'migration name, unique',
@ -418,7 +420,7 @@ CREATE TABLE migrations (
) ENGINE=InnoDB DEFAULT CHARSET=utf8
`
POSTGRES_MIGRATION_DDL = `
POSTGRESMigrationDDL = `
CREATE TYPE migrations_status AS ENUM('update', 'rollback');
CREATE TABLE migrations (

89
new.go
View File

@ -55,7 +55,8 @@ func init() {
}
func createApp(cmd *Command, args []string) int {
curpath, _ := os.Getwd()
ShowShortVersionBanner()
if len(args) != 1 {
ColorLog("[ERRO] Argument [appname] is missing\n")
os.Exit(2)
@ -65,40 +66,12 @@ func createApp(cmd *Command, args []string) int {
Debugf("gopath:%s", gopath)
if gopath == "" {
ColorLog("[ERRO] $GOPATH not found\n")
ColorLog("[HINT] Set $GOPATH in your environment vairables\n")
os.Exit(2)
}
haspath := false
appsrcpath := ""
wgopath := path.SplitList(gopath)
for _, wg := range wgopath {
wg = path.Join(wg, "src")
if strings.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) {
haspath = true
appsrcpath = wg
break
}
wg, _ = path.EvalSymlinks(wg)
if strings.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) {
haspath = true
appsrcpath = wg
break
}
}
if !haspath {
ColorLog("[ERRO] Unable to create an application outside of $GOPATH%ssrc(%s%ssrc)\n", string(path.Separator), gopath, string(path.Separator))
ColorLog("[HINT] Change your work directory by `cd ($GOPATH%ssrc)`\n", string(path.Separator))
ColorLog("[HINT] Set $GOPATH in your environment variables\n")
os.Exit(2)
}
apppath := path.Join(curpath, args[0])
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)
@ -108,47 +81,47 @@ func createApp(cmd *Command, args []string) int {
}
}
fmt.Println("[INFO] Creating application...")
ColorLog("[INFO] Creating application...\n")
os.MkdirAll(apppath, 0755)
fmt.Println(apppath + string(path.Separator))
fmt.Println("\tcreate\t", apppath + string(path.Separator))
os.Mkdir(path.Join(apppath, "conf"), 0755)
fmt.Println(path.Join(apppath, "conf") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "conf") + string(path.Separator))
os.Mkdir(path.Join(apppath, "controllers"), 0755)
fmt.Println(path.Join(apppath, "controllers") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "controllers") + string(path.Separator))
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Println(path.Join(apppath, "models") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "models") + string(path.Separator))
os.Mkdir(path.Join(apppath, "routers"), 0755)
fmt.Println(path.Join(apppath, "routers") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "routers") + string(path.Separator))
os.Mkdir(path.Join(apppath, "tests"), 0755)
fmt.Println(path.Join(apppath, "tests") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "tests") + string(path.Separator))
os.Mkdir(path.Join(apppath, "static"), 0755)
fmt.Println(path.Join(apppath, "static") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "static") + string(path.Separator))
os.Mkdir(path.Join(apppath, "static", "js"), 0755)
fmt.Println(path.Join(apppath, "static", "js") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "static", "js") + string(path.Separator))
os.Mkdir(path.Join(apppath, "static", "css"), 0755)
fmt.Println(path.Join(apppath, "static", "css") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "static", "css") + string(path.Separator))
os.Mkdir(path.Join(apppath, "static", "img"), 0755)
fmt.Println(path.Join(apppath, "static", "img") + string(path.Separator))
fmt.Println(path.Join(apppath, "views") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "static", "img") + string(path.Separator))
fmt.Println("\tcreate\t", path.Join(apppath, "views") + string(path.Separator))
os.Mkdir(path.Join(apppath, "views"), 0755)
fmt.Println(path.Join(apppath, "conf", "app.conf"))
writetofile(path.Join(apppath, "conf", "app.conf"), strings.Replace(appconf, "{{.Appname}}", args[0], -1))
fmt.Println("\tcreate\t", path.Join(apppath, "conf", "app.conf"))
WriteToFile(path.Join(apppath, "conf", "app.conf"), strings.Replace(appconf, "{{.Appname}}", path.Base(args[0]), -1))
fmt.Println(path.Join(apppath, "controllers", "default.go"))
writetofile(path.Join(apppath, "controllers", "default.go"), controllers)
fmt.Println("\tcreate\t", path.Join(apppath, "controllers", "default.go"))
WriteToFile(path.Join(apppath, "controllers", "default.go"), controllers)
fmt.Println(path.Join(apppath, "views", "index.tpl"))
writetofile(path.Join(apppath, "views", "index.tpl"), indextpl)
fmt.Println("\tcreate\t", path.Join(apppath, "views", "index.tpl"))
WriteToFile(path.Join(apppath, "views", "index.tpl"), indextpl)
fmt.Println(path.Join(apppath, "routers", "router.go"))
writetofile(path.Join(apppath, "routers", "router.go"), strings.Replace(router, "{{.Appname}}", strings.Join(strings.Split(apppath[len(appsrcpath)+1:], string(path.Separator)), "/"), -1))
fmt.Println("\tcreate\t", path.Join(apppath, "routers", "router.go"))
WriteToFile(path.Join(apppath, "routers", "router.go"), strings.Replace(router, "{{.Appname}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1))
fmt.Println(path.Join(apppath, "tests", "default_test.go"))
writetofile(path.Join(apppath, "tests", "default_test.go"), strings.Replace(test, "{{.Appname}}", strings.Join(strings.Split(apppath[len(appsrcpath)+1:], string(path.Separator)), "/"), -1))
fmt.Println("\tcreate\t", path.Join(apppath, "tests", "default_test.go"))
WriteToFile(path.Join(apppath, "tests", "default_test.go"), strings.Replace(test, "{{.Appname}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1))
fmt.Println(path.Join(apppath, "main.go"))
writetofile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", strings.Join(strings.Split(apppath[len(appsrcpath)+1:], string(path.Separator)), "/"), -1))
fmt.Println("\tcreate\t", path.Join(apppath, "main.go"))
WriteToFile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1))
ColorLog("[SUCC] New application successfully created!\n")
return 0
@ -336,11 +309,11 @@ var indextpl = `<!DOCTYPE html>
</html>
`
func writetofile(filename, content string) {
func WriteToFile(filename, content string) {
f, err := os.Create(filename)
defer f.Close()
if err != nil {
panic(err)
}
defer f.Close()
f.WriteString(content)
}

32
pack.go
View File

@ -242,13 +242,12 @@ func (wft *walkFileTree) walkLeaf(fpath string, fi os.FileInfo, err error) error
if added, err := wft.wak.compress(name, fpath, fi); added {
if verbose {
fmt.Printf("Compressed: %s\n", name)
fmt.Printf("\t+ Compressed: %s\n", name)
}
wft.allfiles[name] = true
return err
} else {
return err
}
return err
}
func (wft *walkFileTree) iterDirectory(fpath string, fi os.FileInfo) error {
@ -397,10 +396,10 @@ func (wft *zipWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) {
func packDirectory(excludePrefix []string, excludeSuffix []string,
excludeRegexp []*regexp.Regexp, includePath ...string) (err error) {
fmt.Printf("exclude relpath prefix: %s\n", strings.Join(excludePrefix, ":"))
fmt.Printf("exclude relpath suffix: %s\n", strings.Join(excludeSuffix, ":"))
ColorLog("Excluding relpath prefix: %s\n", strings.Join(excludePrefix, ":"))
ColorLog("Excluding relpath suffix: %s\n", strings.Join(excludeSuffix, ":"))
if len(excludeRegexp) > 0 {
fmt.Printf("exclude filename regex: `%s`\n", strings.Join(excludeR, "`, `"))
ColorLog("Excluding filename regex: `%s`\n", strings.Join(excludeR, "`, `"))
}
w, err := os.OpenFile(outputP, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
@ -472,6 +471,8 @@ func isBeegoProject(thePath string) bool {
}
func packApp(cmd *Command, args []string) int {
ShowShortVersionBanner()
curPath, _ := os.Getwd()
thePath := ""
@ -493,17 +494,17 @@ func packApp(cmd *Command, args []string) int {
thePath, err := path.Abs(appPath)
if err != nil {
exitPrint(fmt.Sprintf("wrong app path: %s", thePath))
exitPrint(fmt.Sprintf("Wrong app path: %s", thePath))
}
if stat, err := os.Stat(thePath); os.IsNotExist(err) || stat.IsDir() == false {
exitPrint(fmt.Sprintf("not exist app path: %s", thePath))
exitPrint(fmt.Sprintf("App path does not exist: %s", thePath))
}
if isBeegoProject(thePath) == false {
exitPrint(fmt.Sprintf("not support non beego project"))
exitPrint(fmt.Sprintf("Bee does not support non Beego project"))
}
fmt.Printf("app path: %s\n", thePath)
ColorLog("Packaging application: %s\n", thePath)
appName := path.Base(thePath)
@ -523,8 +524,7 @@ func packApp(cmd *Command, args []string) int {
os.Mkdir(tmpdir, 0700)
if build {
fmt.Println("build", appName)
ColorLog("Building application...\n")
var envs []string
for _, env := range buildEnvs {
parts := strings.SplitN(env, "=", 2)
@ -546,7 +546,7 @@ func packApp(cmd *Command, args []string) int {
os.Setenv("GOOS", goos)
os.Setenv("GOARCH", goarch)
fmt.Println("GOOS", goos, "GOARCH", goarch)
ColorLog("Env: GOOS=%s GOARCH=%s\n", goos, goarch)
binPath := path.Join(tmpdir, appName)
if goos == "windows" {
@ -559,7 +559,7 @@ func packApp(cmd *Command, args []string) int {
}
if verbose {
fmt.Println("go ", strings.Join(args, " "))
fmt.Println("\t+ go", strings.Join(args, " "))
}
execmd := exec.Command("go", args...)
@ -572,7 +572,7 @@ func packApp(cmd *Command, args []string) int {
exitPrint(err.Error())
}
fmt.Println("build success")
ColorLog("Build successful\n")
}
switch format {
@ -624,6 +624,6 @@ func packApp(cmd *Command, args []string) int {
exitPrint(err.Error())
}
fmt.Printf("file write to `%s`\n", outputP)
ColorLog("Writing to output: `%s`\n", outputP)
return 0
}

97
run.go
View File

@ -17,16 +17,14 @@ package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
path "path/filepath"
"runtime"
"strings"
)
var cmdRun = &Command{
UsageLine: "run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true] [-e=Godeps -e=folderToExclude] [-tags=goBuildTags]",
UsageLine: "run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true] [-vendor=true] [-e=folderToExclude] [-tags=goBuildTags]",
Short: "run the app and start a Web server for development",
Long: `
Run command will supervise the file system of the beego project using inotify,
@ -35,16 +33,25 @@ it will recompile and restart the app after any modifications.
`,
}
var mainFiles ListOpts
var downdoc docValue
var gendoc docValue
var (
mainFiles ListOpts
downdoc docValue
gendoc docValue
// The flags list of the paths excluded from watching
var excludedPaths strFlags
excludedPaths strFlags
// Pass through to -tags arg of "go build"
var buildTags string
buildTags string
// Application path
currpath string
// Application name
appname string
// Channel to signal an Exit
exit chan bool
// Flag to watch the vendor folder
vendorWatch bool
// Current user workspace
currentGoPath string
)
func init() {
cmdRun.Run = runApp
@ -52,58 +59,59 @@ func init() {
cmdRun.Flag.Var(&gendoc, "gendoc", "auto generate the docs")
cmdRun.Flag.Var(&downdoc, "downdoc", "auto download swagger file when not exist")
cmdRun.Flag.Var(&excludedPaths, "e", "Excluded paths[].")
cmdRun.Flag.BoolVar(&vendorWatch, "vendor", false, "Watch vendor folder")
cmdRun.Flag.StringVar(&buildTags, "tags", "", "Build tags (https://golang.org/pkg/go/build/)")
exit = make(chan bool)
}
var appname string
func runApp(cmd *Command, args []string) int {
fmt.Println("bee :" + version)
fmt.Println("beego :" + getbeegoVersion())
goversion, err := exec.Command("go", "version").Output()
if err != nil {
log.Fatal(err)
}
fmt.Println("Go :" + string(goversion))
exit := make(chan bool)
crupath, _ := os.Getwd()
ShowShortVersionBanner()
if len(args) == 0 || args[0] == "watchall" {
appname = path.Base(crupath)
ColorLog("[INFO] Uses '%s' as 'appname'\n", appname)
currpath, _ = os.Getwd()
if found, _gopath, _ := SearchGOPATHs(currpath); found {
appname = path.Base(currpath)
currentGoPath = _gopath
} else {
appname = args[0]
ColorLog("[INFO] Uses '%s' as 'appname'\n", appname)
if strings.HasSuffix(appname, ".go") && isExist(path.Join(crupath, appname)) {
ColorLog("[WARN] The appname has conflic with crupath's file, do you want to build appname as %s\n", appname)
exitPrint(fmt.Sprintf("Bee does not support non Beego project: %s", currpath))
}
ColorLog("[INFO] Using '%s' as 'appname'\n", appname)
} else {
// Check if passed Bee application path/name exists in the GOPATH(s)
if found, _gopath, _path := SearchGOPATHs(args[0]); found {
currpath = _path
currentGoPath = _gopath
appname = path.Base(currpath)
} else {
panic(fmt.Sprintf("No Beego application '%s' found in your GOPATH", args[0]))
}
ColorLog("[INFO] Using '%s' as 'appname'\n", appname)
if strings.HasSuffix(appname, ".go") && isExist(currpath) {
ColorLog("[WARN] The appname is in conflict with currpath's file, do you want to build appname as %s\n", appname)
ColorLog("[INFO] Do you want to overwrite it? [yes|no]] ")
if !askForConfirmation() {
return 0
}
}
}
Debugf("current path:%s\n", crupath)
err = loadConfig()
Debugf("current path:%s\n", currpath)
err := loadConfig()
if err != nil {
ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
}
var paths []string
readAppDirectories(crupath, &paths)
readAppDirectories(currpath, &paths)
// Because monitor files has some issues, we watch current directory
// and ignore non-go files.
gps := GetGOPATHs()
if len(gps) == 0 {
ColorLog("[ERRO] Fail to start[ %s ]\n", "$GOPATH is not set or empty")
os.Exit(2)
}
gopath := gps[0]
for _, p := range conf.DirStruct.Others {
paths = append(paths, strings.Replace(p, "$GOPATH", gopath, -1))
paths = append(paths, strings.Replace(p, "$GOPATH", currentGoPath, -1))
}
files := []string{}
@ -121,9 +129,9 @@ func runApp(cmd *Command, args []string) int {
Autobuild(files, false)
}
if downdoc == "true" {
if _, err := os.Stat(path.Join(crupath, "swagger")); err != nil {
if _, err := os.Stat(path.Join(currpath, "swagger")); err != nil {
if os.IsNotExist(err) {
downloadFromUrl(swaggerlink, "swagger.zip")
downloadFromURL(swaggerlink, "swagger.zip")
unzipAndDelete("swagger.zip", "swagger")
}
}
@ -148,6 +156,10 @@ func readAppDirectories(directory string, paths *[]string) {
continue
}
if !vendorWatch && strings.HasSuffix(fileInfo.Name(), "vendor") {
continue
}
if isExcluded(path.Join(directory, fileInfo.Name())) {
continue
}
@ -166,7 +178,6 @@ func readAppDirectories(directory string, paths *[]string) {
useDirectory = true
}
}
return
}

View File

@ -59,7 +59,7 @@ func init() {
func runDocs(cmd *Command, args []string) int {
if isDownload == "true" {
downloadFromUrl(swaggerlink, "swagger.zip")
downloadFromURL(swaggerlink, "swagger.zip")
err := unzipAndDelete("swagger.zip", "swagger")
if err != nil {
fmt.Println("has err exet unzipAndDelete", err)
@ -77,7 +77,7 @@ func runDocs(cmd *Command, args []string) int {
return 0
}
func downloadFromUrl(url, fileName string) {
func downloadFromURL(url, fileName string) {
fmt.Println("Downloading", url, "to", fileName)
output, err := os.Create(fileName)

31
util.go
View File

@ -15,13 +15,14 @@
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"path"
"fmt"
)
// Go is a basic promise implementation: it wraps calls a function in a goroutine
@ -173,6 +174,34 @@ func GetGOPATHs() []string {
return paths
}
func SearchGOPATHs(app string) (bool, string, string) {
gps := GetGOPATHs()
if len(gps) == 0 {
ColorLog("[ERRO] Fail to start [ %s ]\n", "GOPATH environment variable is not set or empty")
os.Exit(2)
}
// Lookup the application inside the user workspace(s)
for _, gopath := range gps {
var currentPath string
if !strings.Contains(app, "src") {
gopathsrc := path.Join(gopath, "src")
currentPath = path.Join(gopathsrc, app)
} else {
currentPath = app
}
if isExist(currentPath) {
if !isBeegoProject(currentPath) {
continue
}
return true, gopath, currentPath
}
}
return false, "", ""
}
// askForConfirmation uses Scanln to parse user input. A user must type in "yes" or "no" and
// then press enter. It has fuzzy matching, so "y", "Y", "yes", "YES", and "Yes" all count as
// confirmations. If the input is not recognized, it will ask again. The function does not return

View File

@ -4,11 +4,10 @@ import (
"bufio"
"fmt"
"io"
"log"
"os"
"os/exec"
path "path/filepath"
"regexp"
"bytes"
)
var cmdVersion = &Command{
@ -25,30 +24,59 @@ bee version
`,
}
const verboseVersionBanner =
`______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v{{ .BeeVersion }}
Beego : {{ .BeegoVersion }}
GoVersion : {{ .GoVersion }}
GOOS : {{ .GOOS }}
GOARCH : {{ .GOARCH }}
NumCPU : {{ .NumCPU }}
GOPATH : {{ .GOPATH }}
GOROOT : {{ .GOROOT }}
Compiler : {{ .Compiler }}
Date : {{ Now "Monday, 2 Jan 2006" }}
`
const shortVersionBanner =
`______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v{{ .BeeVersion }}
`
func init() {
cmdVersion.Run = versionCmd
}
func versionCmd(cmd *Command, args []string) int {
fmt.Println("bee :" + version)
fmt.Println("beego :" + getbeegoVersion())
//fmt.Println("Go :" + runtime.Version())
goversion, err := exec.Command("go", "version").Output()
if err != nil {
log.Fatal(err)
}
fmt.Println("Go :" + string(goversion))
ShowVerboseVersionBanner()
return 0
}
func getbeegoVersion() string {
func ShowVerboseVersionBanner() {
InitBanner(os.Stdout, bytes.NewBufferString(verboseVersionBanner))
}
func ShowShortVersionBanner() {
InitBanner(os.Stdout, bytes.NewBufferString(shortVersionBanner))
}
func getBeegoVersion() string {
gopath := os.Getenv("GOPATH")
re, err := regexp.Compile(`VERSION = "([0-9.]+)"`)
if err != nil {
return ""
}
if gopath == "" {
err = fmt.Errorf("you should set GOPATH in the env")
err = fmt.Errorf("You should set GOPATH env variable")
return ""
}
wgopath := path.SplitList(gopath)
@ -60,11 +88,11 @@ func getbeegoVersion() string {
if os.IsNotExist(err) {
continue
}
ColorLog("[ERRO] get beego.go has error\n")
ColorLog("[ERRO] Get `beego.go` has error\n")
}
fd, err := os.Open(filename)
if err != nil {
ColorLog("[ERRO] open beego.go has error\n")
ColorLog("[ERRO] Open `beego.go` has error\n")
continue
}
reader := bufio.NewReader(fd)
@ -84,5 +112,5 @@ func getbeegoVersion() string {
}
}
return "you don't install beego,install first: github.com/astaxie/beego"
return "Beego not installed. Please install it first: https://github.com/astaxie/beego"
}

View File

@ -121,8 +121,8 @@ func Autobuild(files []string, isgenerate bool) {
defer state.Unlock()
ColorLog("[INFO] Start building...\n")
path, _ := os.Getwd()
os.Chdir(path)
os.Chdir(currpath)
cmdName := "go"
if conf.Gopm.Enable {