diff --git a/.gitignore b/.gitignore index ffab5d0..a4c4e18 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ # Folders _obj _test +.idea # Architecture specific extensions/prefixes *.[568vq] diff --git a/Beefile b/Beefile new file mode 100644 index 0000000..7d682df --- /dev/null +++ b/Beefile @@ -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" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7259aa6 --- /dev/null +++ b/Makefile @@ -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 ./... diff --git a/README.md b/README.md index 5bad9ee..fecb3e9 100644 --- a/README.md +++ b/README.md @@ -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:/bin/bee +export PATH=$PATH:/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"] diff --git a/apiapp.go b/apiapp.go index 8ae376e..ee1f1d0 100644 --- a/apiapp.go +++ b/apiapp.go @@ -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 } diff --git a/bale.go b/bale.go index 336d813..2bf14f9 100644 --- a/bale.go +++ b/bale.go @@ -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 { diff --git a/banner.go b/banner.go new file mode 100644 index 0000000..d04293b --- /dev/null +++ b/banner.go @@ -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(), + }) +} diff --git a/conf.go b/conf.go index 9d610d1..b26f26b 100644 --- a/conf.go +++ b/conf.go @@ -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") } diff --git a/fix.go b/fix.go index b4dbd39..e4adde6 100644 --- a/fix.go +++ b/fix.go @@ -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 } diff --git a/g.go b/g.go index e0eb265..3f36c07 100644 --- a/g.go +++ b/g.go @@ -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 } diff --git a/g_appcode.go b/g_appcode.go index 7860912..9fea762 100644 --- a/g_appcode.go +++ b/g_appcode.go @@ -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) } + 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) } + 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{}, diff --git a/g_controllers.go b/g_controllers.go index 49b5fd9..a4815c0 100644 --- a/g_controllers.go +++ b/g_controllers.go @@ -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) diff --git a/g_docs.go b/g_docs.go index 388cc2f..befcb2e 100644 --- a/g_docs.go +++ b/g_docs.go @@ -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,16 +594,14 @@ 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) + return true, fmt.Sprint(arr.Elt) } + 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 { @@ -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 { diff --git a/g_hproseappcode.go b/g_hproseappcode.go index 86e3d02..7dda6ce 100644 --- a/g_hproseappcode.go +++ b/g_hproseappcode.go @@ -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" diff --git a/g_migration.go b/g_migration.go index d0d296d..d26211c 100644 --- a/g_migration.go +++ b/g_migration.go @@ -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" diff --git a/g_model.go b/g_model.go index 859164f..5c5ce37 100644 --- a/g_model.go +++ b/g_model.go @@ -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": diff --git a/g_scaffold.go b/g_scaffold.go index a9df9d8..ef9b13e 100644 --- a/g_scaffold.go +++ b/g_scaffold.go @@ -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" { - sql = sql + "`id` int(11) NOT NULL AUTO_INCREMENT," - tags = tags + "PRIMARY KEY (`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 "", "" +} diff --git a/g_views.go b/g_views.go index 413c86f..47c252c 100644 --- a/g_views.go +++ b/g_views.go @@ -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) diff --git a/hproseapp.go b/hproseapp.go index 5167c31..8200de6 100644 --- a/hproseapp.go +++ b/hproseapp.go @@ -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 } diff --git a/migrate.go b/migrate.go index 2e3d8b2..0661ae1 100644 --- a/migrate.go +++ b/migrate.go @@ -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 ( diff --git a/new.go b/new.go index bba644d..3a7e87c 100644 --- a/new.go +++ b/new.go @@ -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 = ` ` -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) } diff --git a/pack.go b/pack.go index 9d66088..db2978c 100644 --- a/pack.go +++ b/pack.go @@ -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 } diff --git a/run.go b/run.go index 3d4da70..d4bc44a 100644 --- a/run.go +++ b/run.go @@ -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 - -// The flags list of the paths excluded from watching -var excludedPaths strFlags - -// Pass through to -tags arg of "go build" -var buildTags string +var ( + mainFiles ListOpts + downdoc docValue + gendoc docValue + // The flags list of the paths excluded from watching + excludedPaths strFlags + // Pass through to -tags arg of "go build" + 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 { + exitPrint(fmt.Sprintf("Bee does not support non Beego project: %s", currpath)) + } + ColorLog("[INFO] Using '%s' as 'appname'\n", appname) } 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) + // 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 } diff --git a/rundocs.go b/rundocs.go index 13b0a9a..70a1657 100644 --- a/rundocs.go +++ b/rundocs.go @@ -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) diff --git a/util.go b/util.go index 0f314df..2cd76d3 100644 --- a/util.go +++ b/util.go @@ -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 diff --git a/version.go b/version.go index 23c461f..43931e1 100644 --- a/version.go +++ b/version.go @@ -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" } diff --git a/watch.go b/watch.go index 7d966bd..1b4af32 100644 --- a/watch.go +++ b/watch.go @@ -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 {