From 91c467505afc7b7ba8b5ba24882f7ac1f0e60f05 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Mon, 8 Jul 2013 15:34:58 +0800 Subject: [PATCH 01/30] add api command --- apiapp.go | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 1 + 2 files changed, 167 insertions(+) create mode 100644 apiapp.go diff --git a/apiapp.go b/apiapp.go new file mode 100644 index 0000000..1a44874 --- /dev/null +++ b/apiapp.go @@ -0,0 +1,166 @@ +package main + +import ( + "fmt" + "os" + path "path/filepath" + "strings" +) + +var cmdApiapp = &Command{ + // CustomFlags: true, + UsageLine: "api [appname]", + Short: "create an api application base on beego framework", + Long: ` +create an api application base on beego framework + +In the current path, will create a folder named [appname] + +In the appname folder has the follow struct: + + ├── conf + │   └── app.conf + ├── controllers + │   └── default.go + ├── main.go + └── models + └── default.go + +`, +} + +var apiconf = ` +appname = {{.Appname}} +httpport = 8080 +runmode = dev +autorender = false +` +var apiMaingo = `package main + +import ( + "{{.Appname}}/controllers" + "github.com/astaxie/beego" +) + +func main() { + beego.Router("/", &controllers.MainController{}) + beego.Run() +} +` +var apiModels = `package models + +type User struct { + Name string + Email string +} + +func (this *User) All() (users []User, err error) { + // get all users from DB + // users, err = queryAll() + users = append([]User{}, User{"astaxie", "astaxie@gmail.com"}) + return +} +` + +var apiControllers = `package controllers + +import ( + "{{.Appname}}/models" + "github.com/astaxie/beego" +) + +type MainController struct { + beego.Controller +} + +func (this *MainController) Get() { + var user models.User + users, err := user.All() + if err != nil { + this.Data["json"] = err + } else { + this.Data["json"] = users + } + this.ServeJson() +} +` + +func init() { + cmdApiapp.Run = createapi +} + +func createapi(cmd *Command, args []string) { + if len(args) != 1 { + fmt.Println("error args") + os.Exit(2) + } + apppath, packpath, err := checkEnv(args[0]) + if err != nil { + fmt.Println(err) + os.Exit(2) + } + 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, "models"), 0755) + fmt.Println("create models:", path.Join(apppath, "models")) + + 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)) + + fmt.Println("create controllers default.go:", path.Join(apppath, "controllers", "default.go")) + writetofile(path.Join(apppath, "controllers", "default.go"), + strings.Replace(apiControllers, "{{.Appname}}", packpath, -1)) + + fmt.Println("create models default.go:", path.Join(apppath, "models", "default.go")) + writetofile(path.Join(apppath, "models", "default.go"), apiModels) + + fmt.Println("create main.go:", path.Join(apppath, "main.go")) + writetofile(path.Join(apppath, "main.go"), + strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1)) +} + +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 == "" { + err = fmt.Errorf("you should set GOPATH in the env") + return + } + + appsrcpath := "" + haspath := false + wgopath := path.SplitList(gopath) + for _, wg := range wgopath { + wg = path.Join(wg, "src") + + if path.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) + + if _, e := os.Stat(apppath); os.IsNotExist(e) == false { + err = fmt.Errorf("path `%s` exists, can not create app without remove it\n", apppath) + return + } + packpath = strings.Join(strings.Split(apppath[len(appsrcpath)+1:], string(path.Separator)), "/") + return +} diff --git a/main.go b/main.go index 3749707..6a479f6 100644 --- a/main.go +++ b/main.go @@ -59,6 +59,7 @@ var commands = []*Command{ cmdCreate, cmdStart, cmdPack, + cmdApiapp, //cmdReStart, } From 6bfd839b682b47de558a1d0dc05863b8fe48c55c Mon Sep 17 00:00:00 2001 From: miraclesu Date: Mon, 8 Jul 2013 17:56:48 +0800 Subject: [PATCH 02/30] add api demo --- apiapp.go | 76 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/apiapp.go b/apiapp.go index 1a44874..af78fc3 100644 --- a/apiapp.go +++ b/apiapp.go @@ -43,46 +43,100 @@ import ( ) func main() { - beego.Router("/", &controllers.MainController{}) + beego.Router("/{{.Version}}/users/:objectId", &controllers.UserController{}) + beego.Router("/{{.Version}}/users", &controllers.UserController{}) beego.Run() } ` var apiModels = `package models type User struct { + Id interface{} Name string Email string } +func (this *User) One(id interface{}) (user User, err error) { + // get user from DB + // user, err = query(id) + user = User{id, "astaxie", "astaxie@gmail.com"} + return +} + func (this *User) All() (users []User, err error) { // get all users from DB // users, err = queryAll() - users = append([]User{}, User{"astaxie", "astaxie@gmail.com"}) + users = append([]User{}, User{1, "astaxie", "astaxie@gmail.com"}) + users = append(users, User{2, "someone", "someone@gmail.com"}) return } + +func (this *User) Update(id interface{}) (err error) { + // user, err = update(id, this) + return +} + ` var apiControllers = `package controllers import ( + "encoding/json" "{{.Appname}}/models" "github.com/astaxie/beego" + "io/ioutil" ) -type MainController struct { +type UserController struct { beego.Controller } -func (this *MainController) Get() { +func (this *UserController) Get() { var user models.User - users, err := user.All() - if err != nil { - this.Data["json"] = err + objectId := this.Ctx.Params[":objectId"] + if objectId != "" { + user, err := user.One(objectId) + if err != nil { + this.Data["json"] = err + } else { + this.Data["json"] = user + } } else { - this.Data["json"] = users + users, err := user.All() + if err != nil { + this.Data["json"] = err + } else { + this.Data["json"] = users + } } this.ServeJson() } + +func (this *UserController) Put() { + defer this.ServeJson() + var user models.User + objectId := this.Ctx.Params[":objectId"] + + body, err := ioutil.ReadAll(this.Ctx.Request.Body) + if err != nil { + this.Data["json"] = err + return + } + this.Ctx.Request.Body.Close() + + if err = json.Unmarshal(body, &user); err != nil { + this.Data["json"] = err + return + } + + err = user.Update(objectId) + if err != nil { + this.Data["json"] = err + } else { + this.Data["json"] = "update success!" + } +} + ` func init() { @@ -90,7 +144,10 @@ func init() { } func createapi(cmd *Command, args []string) { - if len(args) != 1 { + version := "1" + if len(args) == 2 { + version = args[1] + } else if len(args) != 1 { fmt.Println("error args") os.Exit(2) } @@ -120,6 +177,7 @@ func createapi(cmd *Command, args []string) { writetofile(path.Join(apppath, "models", "default.go"), apiModels) fmt.Println("create main.go:", path.Join(apppath, "main.go")) + apiMaingo = strings.Replace(apiMaingo, "{{.Version}}", version, -1) writetofile(path.Join(apppath, "main.go"), strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1)) } From b4b8225cbfe32013d253843299580f0ca26da56d Mon Sep 17 00:00:00 2001 From: miraclesu Date: Tue, 9 Jul 2013 15:16:28 +0800 Subject: [PATCH 03/30] an example for api application --- apiapp.go | 145 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 87 insertions(+), 58 deletions(-) diff --git a/apiapp.go b/apiapp.go index af78fc3..d04734f 100644 --- a/apiapp.go +++ b/apiapp.go @@ -24,7 +24,7 @@ In the appname folder has the follow struct: │   └── default.go ├── main.go └── models - └── default.go + └── object.go `, } @@ -34,109 +34,142 @@ appname = {{.Appname}} httpport = 8080 runmode = dev autorender = false +copyrequestbody = true ` var apiMaingo = `package main import ( - "{{.Appname}}/controllers" "github.com/astaxie/beego" + "{{.Appname}}/controllers" ) +// Objects + +// URL HTTP Verb Functionality +// /object POST Creating Objects +// /object/ GET Retrieving Objects +// /object/ PUT Updating Objects +// /object GET Queries +// /object/ DELETE Deleting Objects + func main() { - beego.Router("/{{.Version}}/users/:objectId", &controllers.UserController{}) - beego.Router("/{{.Version}}/users", &controllers.UserController{}) + beego.RESTRouter("/object", &controllers.ObejctController{}) beego.Run() } ` var apiModels = `package models -type User struct { - Id interface{} - Name string - Email string +import ( + "errors" + "strconv" + "time" +) + +var ( + Objects map[string]*Object +) + +type Object struct { + ObjectId string + Score int64 + PlayerName string } -func (this *User) One(id interface{}) (user User, err error) { - // get user from DB - // user, err = query(id) - user = User{id, "astaxie", "astaxie@gmail.com"} - return +func init() { + Objects = make(map[string]*Object) + Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"} + Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"} } -func (this *User) All() (users []User, err error) { - // get all users from DB - // users, err = queryAll() - users = append([]User{}, User{1, "astaxie", "astaxie@gmail.com"}) - users = append(users, User{2, "someone", "someone@gmail.com"}) - return +func AddOne(object Object) (ObjectId string) { + object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10) + Objects[object.ObjectId] = &object + return object.ObjectId } -func (this *User) Update(id interface{}) (err error) { - // user, err = update(id, this) - return +func GetOne(ObjectId string) (object *Object, err error) { + if v, ok := Objects[ObjectId]; ok { + return v, nil + } + return nil, errors.New("ObjectId Not Exist") } +func GetAll() map[string]*Object { + return Objects +} + +func Update(ObjectId string, Score int64) (err error) { + if v, ok := Objects[ObjectId]; ok { + v.Score = Score + return nil + } + return errors.New("ObjectId Not Exist") +} + +func Delete(ObjectId string) { + delete(Objects, ObjectId) +} ` var apiControllers = `package controllers import ( "encoding/json" - "{{.Appname}}/models" "github.com/astaxie/beego" - "io/ioutil" + "{{.Appname}}/models" ) -type UserController struct { +type ResponseInfo struct { +} + +type ObejctController struct { beego.Controller } -func (this *UserController) Get() { - var user models.User +func (this *ObejctController) Post() { + var ob models.Object + json.Unmarshal(this.Ctx.RequestBody, &ob) + objectid := models.AddOne(ob) + this.Data["json"] = "{\"ObjectId\":\"" + objectid + "\"}" + this.ServeJson() +} + +func (this *ObejctController) Get() { objectId := this.Ctx.Params[":objectId"] if objectId != "" { - user, err := user.One(objectId) + ob, err := models.GetOne(objectId) if err != nil { this.Data["json"] = err } else { - this.Data["json"] = user + this.Data["json"] = ob } } else { - users, err := user.All() - if err != nil { - this.Data["json"] = err - } else { - this.Data["json"] = users - } + obs := models.GetAll() + this.Data["json"] = obs } this.ServeJson() } -func (this *UserController) Put() { - defer this.ServeJson() - var user models.User +func (this *ObejctController) Put() { objectId := this.Ctx.Params[":objectId"] + var ob models.Object + json.Unmarshal(this.Ctx.RequestBody, &ob) - body, err := ioutil.ReadAll(this.Ctx.Request.Body) - if err != nil { - this.Data["json"] = err - return - } - this.Ctx.Request.Body.Close() - - if err = json.Unmarshal(body, &user); err != nil { - this.Data["json"] = err - return - } - - err = user.Update(objectId) + err := models.Update(objectId, ob.Score) if err != nil { this.Data["json"] = err } else { this.Data["json"] = "update success!" } + this.ServeJson() } +func (this *ObejctController) Delete() { + objectId := this.Ctx.Params[":objectId"] + models.Delete(objectId) + this.Data["json"] = "delete success!" + this.ServeJson() +} ` func init() { @@ -144,10 +177,7 @@ func init() { } func createapi(cmd *Command, args []string) { - version := "1" - if len(args) == 2 { - version = args[1] - } else if len(args) != 1 { + if len(args) != 1 { fmt.Println("error args") os.Exit(2) } @@ -173,11 +203,10 @@ func createapi(cmd *Command, args []string) { writetofile(path.Join(apppath, "controllers", "default.go"), strings.Replace(apiControllers, "{{.Appname}}", packpath, -1)) - fmt.Println("create models default.go:", path.Join(apppath, "models", "default.go")) - writetofile(path.Join(apppath, "models", "default.go"), apiModels) + fmt.Println("create models object.go:", path.Join(apppath, "models", "object.go")) + writetofile(path.Join(apppath, "models", "object.go"), apiModels) fmt.Println("create main.go:", path.Join(apppath, "main.go")) - apiMaingo = strings.Replace(apiMaingo, "{{.Version}}", version, -1) writetofile(path.Join(apppath, "main.go"), strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1)) } From 2a71bd26039140e71ba17293d2586c9169334630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=A8=E9=A0=AD?= Date: Mon, 22 Jul 2013 17:17:08 +0800 Subject: [PATCH 04/30] fixed: Support bee start appname && bee start ./appname --- watch.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/watch.go b/watch.go index 3188777..418e491 100644 --- a/watch.go +++ b/watch.go @@ -8,6 +8,7 @@ import ( "os/exec" "sync" "time" + "strings" ) var ( @@ -94,6 +95,10 @@ func Restart(appname string) { func Start(appname string) { fmt.Println("start", appname) + + if strings.Index(appname, "./") == -1 { + appname = "./" + appname + } cmd = exec.Command(appname) cmd.Stdout = os.Stdout From 0feb778d4dd0fe20b49f17596d8d9ff927bd9cbc Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 24 Jul 2013 14:58:13 +0800 Subject: [PATCH 05/30] skip TMP files and gofmt events --- watch.go | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/watch.go b/watch.go index 418e491..012fc4f 100644 --- a/watch.go +++ b/watch.go @@ -6,9 +6,9 @@ import ( "log" "os" "os/exec" + "strings" "sync" "time" - "strings" ) var ( @@ -28,14 +28,21 @@ func NewWatcher(paths []string) { select { case e := <-watcher.Event: isbuild := true - if t, ok := eventTime[e.String()]; ok { + + // Skip TMP files for Sublime Text. + if checkTMPFile(e.Name) { + continue + } + + if t, ok := eventTime[e.Name]; ok { // if 500ms change many times, then ignore it. // for liteide often gofmt code after save. if t.Add(time.Millisecond * 500).After(time.Now()) { + fmt.Println("[SKIP]", e.String()) isbuild = false } } - eventTime[e.String()] = time.Now() + eventTime[e.Name] = time.Now() if isbuild { fmt.Println(e) @@ -95,7 +102,7 @@ func Restart(appname string) { func Start(appname string) { fmt.Println("start", appname) - + if strings.Index(appname, "./") == -1 { appname = "./" + appname } @@ -106,3 +113,11 @@ func Start(appname string) { go cmd.Run() } + +// checkTMPFile returns true if the event was for TMP files. +func checkTMPFile(name string) bool { + if strings.HasSuffix(strings.ToLower(name), ".tmp") { + return true + } + return false +} From 9e9f0ce1dd772ddf01b70b65e1b9743d0f36fcc5 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 24 Jul 2013 19:20:30 +0800 Subject: [PATCH 06/30] Update tpl file and code for create new Beego application --- createapp.go | 165 ----------------------------------- main.go | 3 +- new.go | 242 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 244 insertions(+), 166 deletions(-) delete mode 100644 createapp.go create mode 100644 new.go diff --git a/createapp.go b/createapp.go deleted file mode 100644 index 7c2fce9..0000000 --- a/createapp.go +++ /dev/null @@ -1,165 +0,0 @@ -package main - -import ( - "fmt" - "os" - path "path/filepath" - "strings" -) - -var cmdCreate = &Command{ - UsageLine: "create [appname]", - Short: "create an application base on beego framework", - Long: ` -create an application base on beego framework - -In the current path, will create a folder named [appname] - -In the appname folder has the follow struct: - - |- main.go - |- conf - |- app.conf - |- controllers - |- default.go - |- models - |- static - |- js - |- css - |- img - |- views - index.tpl - -`, -} - -func init() { - cmdCreate.Run = createapp -} - -func createapp(cmd *Command, args []string) { - curpath, _ := os.Getwd() - if len(args) != 1 { - fmt.Println("error args") - os.Exit(2) - } - - gopath := os.Getenv("GOPATH") - Debugf("gopath:%s", gopath) - if gopath == "" { - fmt.Println("you should set GOPATH in the env") - os.Exit(2) - } - haspath := false - appsrcpath := "" - - wgopath := path.SplitList(gopath) - for _, wg := range wgopath { - wg = path.Join(wg, "src") - - if path.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) { - haspath = true - appsrcpath = wg - break - } - } - - if !haspath { - fmt.Printf("can't create application outside of GOPATH `%s`\n", gopath) - fmt.Printf("you first should `cd $GOPATH%ssrc` then use create\n", string(path.Separator)) - os.Exit(2) - } - - apppath := path.Join(curpath, args[0]) - - if _, err := os.Stat(apppath); os.IsNotExist(err) == false { - fmt.Printf("path `%s` exists, can not create app without remove it\n", apppath) - os.Exit(2) - } - - 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, "models"), 0755) - fmt.Println("create models:", path.Join(apppath, "models")) - os.Mkdir(path.Join(apppath, "static"), 0755) - fmt.Println("create static:", path.Join(apppath, "static")) - os.Mkdir(path.Join(apppath, "static", "js"), 0755) - fmt.Println("create static js:", path.Join(apppath, "static", "js")) - os.Mkdir(path.Join(apppath, "static", "css"), 0755) - fmt.Println("create static css:", path.Join(apppath, "static", "css")) - os.Mkdir(path.Join(apppath, "static", "img"), 0755) - fmt.Println("create static img:", path.Join(apppath, "static", "img")) - fmt.Println("create views:", path.Join(apppath, "views")) - os.Mkdir(path.Join(apppath, "views"), 0755) - fmt.Println("create conf app.conf:", path.Join(apppath, "conf", "app.conf")) - writetofile(path.Join(apppath, "conf", "app.conf"), strings.Replace(appconf, "{{.Appname}}", args[0], -1)) - - fmt.Println("create controllers default.go:", path.Join(apppath, "controllers", "default.go")) - writetofile(path.Join(apppath, "controllers", "default.go"), controllers) - - fmt.Println("create views index.tpl:", path.Join(apppath, "views", "index.tpl")) - writetofile(path.Join(apppath, "views", "index.tpl"), indextpl) - - fmt.Println("create main.go:", 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)) -} - -var appconf = ` -appname = {{.Appname}} -httpport = 8080 -runmode = dev -` - -var maingo = `package main - -import ( - "{{.Appname}}/controllers" - "github.com/astaxie/beego" -) - -func main() { - beego.Router("/", &controllers.MainController{}) - beego.Run() -} - -` -var controllers = `package controllers - -import ( - "github.com/astaxie/beego" -) - -type MainController struct { - beego.Controller -} - -func (this *MainController) Get() { - this.Data["Username"] = "astaxie" - this.Data["Email"] = "astaxie@gmail.com" - this.TplNames = "index.tpl" -} -` - -var indextpl = ` - - - beego welcome template - - -

Hello, world!{{.Username}},{{.Email}}

- - -` - -func writetofile(filename, content string) { - f, err := os.Create(filename) - if err != nil { - panic(err) - } - defer f.Close() - f.WriteString(content) -} diff --git a/main.go b/main.go index 6a479f6..091ebd4 100644 --- a/main.go +++ b/main.go @@ -1,3 +1,4 @@ +// Bee is a tool for developling applications based on beego framework. package main import ( @@ -56,7 +57,7 @@ func (c *Command) Runnable() bool { } var commands = []*Command{ - cmdCreate, + cmdNew, cmdStart, cmdPack, cmdApiapp, diff --git a/new.go b/new.go new file mode 100644 index 0000000..63ee0d9 --- /dev/null +++ b/new.go @@ -0,0 +1,242 @@ +package main + +import ( + "fmt" + "os" + path "path/filepath" + "strings" +) + +var cmdNew = &Command{ + UsageLine: "new [appname]", + Short: "create an application base on beego framework", + Long: ` +create an application base on beego framework, + +which in the current path with folder named [appname]. + +The [appname] folder has following structure: + + |- main.go + |- conf + |- app.conf + |- controllers + |- default.go + |- models + |- static + |- js + |- css + |- img + |- views + index.tpl + +`, +} + +func init() { + cmdNew.Run = createApp +} + +func createApp(cmd *Command, args []string) { + curpath, _ := os.Getwd() + if len(args) != 1 { + fmt.Println("[ERRO] Argument [appname] is missing") + os.Exit(2) + } + + gopath := os.Getenv("GOPATH") + Debugf("gopath:%s", gopath) + if gopath == "" { + fmt.Printf("[ERRO] $GOPATH not found\n") + fmt.Printf("[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 path.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) { + haspath = true + appsrcpath = wg + break + } + } + + if !haspath { + fmt.Printf("[ERRO] Unable to create an application outside of $GOPATH(%s)\n", gopath) + fmt.Printf("[HINT] Change your work directory by `cd $GOPATH%ssrc`\n", string(path.Separator)) + os.Exit(2) + } + + apppath := path.Join(curpath, args[0]) + + if _, err := os.Stat(apppath); os.IsNotExist(err) == false { + fmt.Printf("[ERRO] Path(%s) has alreay existed\n", apppath) + os.Exit(2) + } + + fmt.Println("[INFO] Creating application...") + + os.MkdirAll(apppath, 0755) + fmt.Println(apppath + string(path.Separator)) + os.Mkdir(path.Join(apppath, "conf"), 0755) + fmt.Println(path.Join(apppath, "conf") + string(path.Separator)) + os.Mkdir(path.Join(apppath, "controllers"), 0755) + fmt.Println(path.Join(apppath, "controllers") + string(path.Separator)) + os.Mkdir(path.Join(apppath, "models"), 0755) + fmt.Println(path.Join(apppath, "models") + string(path.Separator)) + os.Mkdir(path.Join(apppath, "static"), 0755) + fmt.Println(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)) + os.Mkdir(path.Join(apppath, "static", "css"), 0755) + fmt.Println(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)) + 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(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(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)), string(path.Separator)), -1)) + + fmt.Println("[SUCC] New application successfully created!") +} + +var appconf = `appname = {{.Appname}} +httpport = 8080 +runmode = dev +` + +var maingo = `package main + +import ( + "{{.Appname}}/controllers" + "github.com/astaxie/beego" +) + +func main() { + beego.Router("/", &controllers.MainController{}) + beego.Run() +} + +` +var controllers = `package controllers + +import ( + "github.com/astaxie/beego" +) + +type MainController struct { + beego.Controller +} + +func (this *MainController) Get() { + this.Data["Website"] = "beego.me" + this.Data["Email"] = "astaxie@gmail.com" + this.TplNames = "index.tpl" +} +` + +var indextpl = ` + + + + Beego + + + + + + +
+
+
+
+

Welcome to Beego!

+

+ Beego is a simple & powerful Go web framework which is inspired by tornado and sinatra. +
+ Official website: {{.Website}} +
+ Contact me: {{.Email}} +

+
+
+
+
+ + +` + +func writetofile(filename, content string) { + f, err := os.Create(filename) + if err != nil { + panic(err) + } + defer f.Close() + f.WriteString(content) +} From 172bc44b22709d83140191933657660721d678f2 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 24 Jul 2013 20:01:14 +0800 Subject: [PATCH 07/30] Add user conf support for bee.json --- main.go => bee.go | 2 +- bee.json | 5 +++ run.go | 93 +++++++++++++++++++++++++++++++++++++++++++++++ start.go | 54 --------------------------- watch.go | 11 +++--- 5 files changed, 104 insertions(+), 61 deletions(-) rename main.go => bee.go (99%) create mode 100644 bee.json create mode 100644 run.go delete mode 100644 start.go diff --git a/main.go b/bee.go similarity index 99% rename from main.go rename to bee.go index 091ebd4..1ad6cb7 100644 --- a/main.go +++ b/bee.go @@ -58,7 +58,7 @@ func (c *Command) Runnable() bool { var commands = []*Command{ cmdNew, - cmdStart, + cmdRun, cmdPack, cmdApiapp, //cmdReStart, diff --git a/bee.json b/bee.json new file mode 100644 index 0000000..51dcd07 --- /dev/null +++ b/bee.json @@ -0,0 +1,5 @@ +{ + "dir_structure":{ + "controllers": "routers" + } +} \ No newline at end of file diff --git a/run.go b/run.go new file mode 100644 index 0000000..212652e --- /dev/null +++ b/run.go @@ -0,0 +1,93 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + path "path/filepath" + "runtime" +) + +var cmdRun = &Command{ + UsageLine: "run [appname]", + Short: "run the app which can hot compile", + Long: ` +start the appname throw exec.Command + +then start a inotify watch for current dir + +when the file has changed bee will auto go build and restart the app + + file changed + | + check if it's go file + | + yes no + | | + go build do nothing + | + restart app +`, +} + +func init() { + cmdRun.Run = runApp +} + +var appname string +var conf struct { + DirStruct struct { + Controllers string + Models string + } `json:"dir_structure"` +} + +func runApp(cmd *Command, args []string) { + if len(args) != 1 { + fmt.Println("[ERRO] Argument [appname] is missing") + os.Exit(2) + } + crupath, _ := os.Getwd() + Debugf("current path:%s\n", crupath) + + err := loadConfig() + if err != nil { + fmt.Println("[ERRO] Fail to parse bee.json:", err) + } + var paths []string + paths = append(paths, + path.Join(crupath, conf.DirStruct.Controllers), + path.Join(crupath, conf.DirStruct.Models)) + + NewWatcher(paths) + appname = args[0] + Autobuild() + for { + runtime.Gosched() + } +} + +// loadConfig loads customized configuration. +func loadConfig() error { + f, err := os.Open("bee.json") + if err != nil { + // Use default. + return nil + } + defer f.Close() + + d := json.NewDecoder(f) + err = d.Decode(&conf) + if err != nil { + return err + } + + // Set variables. + if len(conf.DirStruct.Controllers) == 0 { + conf.DirStruct.Controllers = "controllers" + } + if len(conf.DirStruct.Models) == 0 { + conf.DirStruct.Models = "models" + } + return nil +} diff --git a/start.go b/start.go deleted file mode 100644 index 4e8acef..0000000 --- a/start.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "fmt" - "os" - path "path/filepath" - "runtime" -) - -var cmdStart = &Command{ - UsageLine: "start [appname]", - Short: "start the app which can hot compile", - Long: ` -start the appname throw exec.Command - -then start a inotify watch for current dir - -when the file has changed bee will auto go build and restart the app - - file changed - | - checked is go file - | - yes no - | | - go build do nothing - | - restart app -`, -} - -func init() { - cmdStart.Run = startapp -} - -var appname string - -func startapp(cmd *Command, args []string) { - if len(args) != 1 { - fmt.Println("error args") - os.Exit(2) - } - crupath, _ := os.Getwd() - Debugf("current path:%s\n", crupath) - - var paths []string - paths = append(paths, path.Join(crupath, "controllers"), path.Join(crupath, "models")) - NewWatcher(paths) - appname = args[0] - Autobuild() - for { - runtime.Gosched() - } -} diff --git a/watch.go b/watch.go index 012fc4f..5fa0c02 100644 --- a/watch.go +++ b/watch.go @@ -45,7 +45,7 @@ func NewWatcher(paths []string) { eventTime[e.Name] = time.Now() if isbuild { - fmt.Println(e) + fmt.Println("[EVEN]", e) go Autobuild() } case err := <-watcher.Error: @@ -67,7 +67,7 @@ func Autobuild() { state.Lock() defer state.Unlock() - fmt.Println("start autobuild") + fmt.Println("[INFO] Start building...") path, _ := os.Getwd() os.Chdir(path) bcmd := exec.Command("go", "build") @@ -76,10 +76,10 @@ func Autobuild() { err := bcmd.Run() if err != nil { - fmt.Println("============== build failed ===================") + fmt.Println("[ERRO] ============== Build failed ===================") return } - fmt.Println("build success") + fmt.Println("[SUCC] Build was successful") Restart(appname) } @@ -101,8 +101,7 @@ func Restart(appname string) { } func Start(appname string) { - fmt.Println("start", appname) - + fmt.Println("[INFO] Restarting", appname) if strings.Index(appname, "./") == -1 { appname = "./" + appname } From ead4f9fd81dbb23522b9e20a8a98630f232c55e2 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 24 Jul 2013 20:36:22 +0800 Subject: [PATCH 08/30] Add support for watch main package files through bee.json --- bee.json | 8 ++++++-- run.go | 2 ++ watch.go | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/bee.json b/bee.json index 51dcd07..164b7f6 100644 --- a/bee.json +++ b/bee.json @@ -1,5 +1,9 @@ { "dir_structure":{ - "controllers": "routers" - } + "controllers": "", + "models": "" + }, + "files": [ + "main.go" + ] } \ No newline at end of file diff --git a/run.go b/run.go index 212652e..4b3b3be 100644 --- a/run.go +++ b/run.go @@ -40,6 +40,7 @@ var conf struct { Controllers string Models string } `json:"dir_structure"` + Files []string } func runApp(cmd *Command, args []string) { @@ -58,6 +59,7 @@ func runApp(cmd *Command, args []string) { paths = append(paths, path.Join(crupath, conf.DirStruct.Controllers), path.Join(crupath, conf.DirStruct.Models)) + paths = append(paths, conf.Files...) NewWatcher(paths) appname = args[0] diff --git a/watch.go b/watch.go index 5fa0c02..db6bc0b 100644 --- a/watch.go +++ b/watch.go @@ -53,6 +53,8 @@ func NewWatcher(paths []string) { } } }() + + fmt.Println("[INFO] Initializing watcher...") for _, path := range paths { fmt.Println(path) err = watcher.Watch(path) From 422e2dc7374f0445f0b6f01a56eed5ca9367ce9a Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 25 Jul 2013 16:26:54 +0800 Subject: [PATCH 09/30] Add option go install --- bee.json | 1 + run.go | 3 +++ watch.go | 21 +++++++++++++++++---- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/bee.json b/bee.json index 164b7f6..b8e8a23 100644 --- a/bee.json +++ b/bee.json @@ -1,4 +1,5 @@ { + "go_install": false, "dir_structure":{ "controllers": "", "models": "" diff --git a/run.go b/run.go index 4b3b3be..f9ba02e 100644 --- a/run.go +++ b/run.go @@ -36,6 +36,8 @@ func init() { var appname string var conf struct { + // Indicates whether execute "go install" before "go build". + GoInstall bool `json:"go_install"` DirStruct struct { Controllers string Models string @@ -71,6 +73,7 @@ func runApp(cmd *Command, args []string) { // loadConfig loads customized configuration. func loadConfig() error { + fmt.Println("[INFO] Detect bee.json") f, err := os.Open("bee.json") if err != nil { // Use default. diff --git a/watch.go b/watch.go index db6bc0b..98430d2 100644 --- a/watch.go +++ b/watch.go @@ -72,10 +72,23 @@ func Autobuild() { fmt.Println("[INFO] Start building...") path, _ := os.Getwd() os.Chdir(path) - bcmd := exec.Command("go", "build") - bcmd.Stdout = os.Stdout - bcmd.Stderr = os.Stderr - err := bcmd.Run() + + var err error + // For applications use full import path like "github.com/.../.." + // are able to use "go install" to reduce build time. + if conf.GoInstall { + icmd := exec.Command("go", "install") + icmd.Stdout = os.Stdout + icmd.Stderr = os.Stderr + err = icmd.Run() + } + + if err == nil { + bcmd := exec.Command("go", "build") + bcmd.Stdout = os.Stdout + bcmd.Stderr = os.Stderr + err = bcmd.Run() + } if err != nil { fmt.Println("[ERRO] ============== Build failed ===================") From 7ea67b5534b911c2ae72ba41722563e525b06a68 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 27 Jul 2013 09:44:44 +0800 Subject: [PATCH 10/30] Added func getControllerInfo --- README.md | 7 +- autorouter.go | 282 ++++++++++++++++++++++++++++++++++++++ autorouter_test.go | 9 ++ bee.go | 15 ++ bee.json | 10 +- code.go | 262 +++++++++++++++++++++++++++++++++++ run.go | 17 ++- testdata/router/router.go | 28 ++++ 8 files changed, 622 insertions(+), 8 deletions(-) create mode 100644 autorouter.go create mode 100644 autorouter_test.go create mode 100644 code.go create mode 100644 testdata/router/router.go diff --git a/README.md b/README.md index 2007357..28b76ff 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ bee === + [![Build Status](https://drone.io/github.com/astaxie/bee/status.png)](https://drone.io/github.com/astaxie/bee/latest) -Bee is a tool for managing beego framework. \ No newline at end of file +Bee is a tool for managing beego framework. + +## License + +[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). \ No newline at end of file diff --git a/autorouter.go b/autorouter.go new file mode 100644 index 0000000..2de7bfb --- /dev/null +++ b/autorouter.go @@ -0,0 +1,282 @@ +// Copyright 2013 Bee Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package main + +import ( + "bytes" + "errors" + "fmt" + "go/ast" + gobuild "go/build" + "go/doc" + "go/parser" + "go/token" + "io" + "io/ioutil" + "os" + "path" + "runtime" + "strings" + "time" +) + +var cmdRouter = &Command{ + UsageLine: "router", + Short: "auto-generate routers for the app controllers", + Long: ` + +`, +} + +func init() { + cmdRouter.Run = autoRouter +} + +func autoRouter(cmd *Command, args []string) { + fmt.Println("[INFO] Starting auto-generating routers...") +} + +// getControllerInfo returns controllers that embeded "beego.controller" +// and their methods of package in given path. +func getControllerInfo(path string) (map[string][]string, error) { + now := time.Now() + path = strings.TrimSuffix(path, "/") + dir, err := os.Open(path) + if err != nil { + return nil, err + } + + fis, err := dir.Readdir(0) + if err != nil { + return nil, err + } + + files := make([]*source, 0, len(fis)) + for _, fi := range fis { + // Only load go files. + if strings.HasSuffix(fi.Name(), ".go") { + f, err := os.Open(path + "/" + fi.Name()) + if err != nil { + return nil, err + } + + p := make([]byte, fi.Size()) + _, err = f.Read(p) + if err != nil { + return nil, err + } + + f.Close() + files = append(files, &source{ + name: path + "/" + fi.Name(), + data: p, + }) + } + } + + rw := &routerWalker{ + pdoc: &Package{ + ImportPath: path, + }, + } + + cm := make(map[string][]string) + pdoc, err := rw.build(files) + for _, t := range pdoc.Types { + // Check if embeded "beego.Controller". + if strings.Index(t.Decl, "beego.Controller") > -1 { + for _, f := range t.Methods { + cm[t.Name] = append(cm[t.Name], f.Name) + } + } + } + fmt.Println(time.Since(now)) + return cm, nil +} + +// A source describles a source code file. +type source struct { + name string + data []byte +} + +func (s *source) Name() string { return s.name } +func (s *source) Size() int64 { return int64(len(s.data)) } +func (s *source) Mode() os.FileMode { return 0 } +func (s *source) ModTime() time.Time { return time.Time{} } +func (s *source) IsDir() bool { return false } +func (s *source) Sys() interface{} { return nil } + +// A routerWalker holds the state used when building the documentation. +type routerWalker struct { + pdoc *Package + srcs map[string]*source // Source files. + fset *token.FileSet + buf []byte // scratch space for printNode method. +} + +// Package represents full information and documentation for a package. +type Package struct { + ImportPath string + + // Top-level declarations. + Types []*Type +} + +// Type represents structs and interfaces. +type Type struct { + Name string // Type name. + Decl string + Methods []*Func // Exported methods. +} + +// Func represents functions +type Func struct { + Name string +} + +// build generates data from source files. +func (w *routerWalker) build(srcs []*source) (*Package, error) { + // Add source files to walker, I skipped references here. + w.srcs = make(map[string]*source) + for _, src := range srcs { + w.srcs[src.name] = src + } + + w.fset = token.NewFileSet() + + // Find the package and associated files. + ctxt := gobuild.Context{ + GOOS: runtime.GOOS, + GOARCH: runtime.GOARCH, + CgoEnabled: true, + JoinPath: path.Join, + IsAbsPath: path.IsAbs, + SplitPathList: func(list string) []string { return strings.Split(list, ":") }, + IsDir: func(path string) bool { panic("unexpected") }, + HasSubdir: func(root, dir string) (rel string, ok bool) { panic("unexpected") }, + ReadDir: func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) }, + OpenFile: func(path string) (r io.ReadCloser, err error) { return w.openFile(path) }, + Compiler: "gc", + } + + bpkg, err := ctxt.ImportDir(w.pdoc.ImportPath, 0) + // Continue if there are no Go source files; we still want the directory info. + _, nogo := err.(*gobuild.NoGoError) + if err != nil { + if nogo { + err = nil + } else { + return nil, errors.New("routerWalker.build -> " + err.Error()) + } + } + + // Parse the Go files + files := make(map[string]*ast.File) + for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) { + file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments) + if err != nil { + return nil, errors.New("routerWalker.build -> parse go files: " + err.Error()) + } + files[name] = file + } + + apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil) + + mode := doc.Mode(0) + if w.pdoc.ImportPath == "builtin" { + mode |= doc.AllDecls + } + + pdoc := doc.New(apkg, w.pdoc.ImportPath, mode) + + w.pdoc.Types = w.types(pdoc.Types) + + return w.pdoc, err +} + +func (w *routerWalker) funcs(fdocs []*doc.Func) []*Func { + var result []*Func + for _, d := range fdocs { + result = append(result, &Func{ + Name: d.Name, + }) + } + return result +} + +func (w *routerWalker) types(tdocs []*doc.Type) []*Type { + var result []*Type + for _, d := range tdocs { + result = append(result, &Type{ + Decl: w.printDecl(d.Decl), + Name: d.Name, + Methods: w.funcs(d.Methods), + }) + } + return result +} + +func (w *routerWalker) printDecl(decl ast.Node) string { + var d Code + d, w.buf = printDecl(decl, w.fset, w.buf) + return d.Text +} + +func (w *routerWalker) readDir(dir string) ([]os.FileInfo, error) { + if dir != w.pdoc.ImportPath { + panic("unexpected") + } + fis := make([]os.FileInfo, 0, len(w.srcs)) + for _, src := range w.srcs { + fis = append(fis, src) + } + return fis, nil +} + +func (w *routerWalker) openFile(path string) (io.ReadCloser, error) { + if strings.HasPrefix(path, w.pdoc.ImportPath+"/") { + if src, ok := w.srcs[path[len(w.pdoc.ImportPath)+1:]]; ok { + return ioutil.NopCloser(bytes.NewReader(src.data)), nil + } + } + panic("unexpected") +} + +func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) { + pkg := imports[path] + if pkg == nil { + // Guess the package name without importing it. Start with the last + // element of the path. + name := path[strings.LastIndex(path, "/")+1:] + + // Trim commonly used prefixes and suffixes containing illegal name + // runes. + name = strings.TrimSuffix(name, ".go") + name = strings.TrimSuffix(name, "-go") + name = strings.TrimPrefix(name, "go.") + name = strings.TrimPrefix(name, "go-") + name = strings.TrimPrefix(name, "biogo.") + + // It's also common for the last element of the path to contain an + // extra "go" prefix, but not always. TODO: examine unresolved ids to + // detect when trimming the "go" prefix is appropriate. + + pkg = ast.NewObj(ast.Pkg, name) + pkg.Data = ast.NewScope(nil) + imports[path] = pkg + } + return pkg, nil +} diff --git a/autorouter_test.go b/autorouter_test.go new file mode 100644 index 0000000..437f3ee --- /dev/null +++ b/autorouter_test.go @@ -0,0 +1,9 @@ +package main + +import ( + "testing" +) + +func TestGetControllerInfo(t *testing.T) { + getControllerInfo("testdata/router/") +} diff --git a/bee.go b/bee.go index 1ad6cb7..5450aea 100644 --- a/bee.go +++ b/bee.go @@ -1,3 +1,17 @@ +// Copyright 2013 Bee Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + // Bee is a tool for developling applications based on beego framework. package main @@ -61,6 +75,7 @@ var commands = []*Command{ cmdRun, cmdPack, cmdApiapp, + cmdRouter, //cmdReStart, } diff --git a/bee.json b/bee.json index b8e8a23..8b21388 100644 --- a/bee.json +++ b/bee.json @@ -2,9 +2,11 @@ "go_install": false, "dir_structure":{ "controllers": "", - "models": "" + "models": "", + "others": [] }, - "files": [ - "main.go" - ] + "main_files":{ + "main.go": "", + "others": [] + } } \ No newline at end of file diff --git a/code.go b/code.go new file mode 100644 index 0000000..5e4c3e2 --- /dev/null +++ b/code.go @@ -0,0 +1,262 @@ +// Copyright 2011 Gary Burd +// Copyright 2013 Unknown +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package main + +import ( + "go/ast" + "go/printer" + "go/scanner" + "go/token" + "math" + "strconv" +) + +const ( + notPredeclared = iota + predeclaredType + predeclaredConstant + predeclaredFunction +) + +// predeclared represents the set of all predeclared identifiers. +var predeclared = map[string]int{ + "bool": predeclaredType, + "byte": predeclaredType, + "complex128": predeclaredType, + "complex64": predeclaredType, + "error": predeclaredType, + "float32": predeclaredType, + "float64": predeclaredType, + "int16": predeclaredType, + "int32": predeclaredType, + "int64": predeclaredType, + "int8": predeclaredType, + "int": predeclaredType, + "rune": predeclaredType, + "string": predeclaredType, + "uint16": predeclaredType, + "uint32": predeclaredType, + "uint64": predeclaredType, + "uint8": predeclaredType, + "uint": predeclaredType, + "uintptr": predeclaredType, + + "true": predeclaredConstant, + "false": predeclaredConstant, + "iota": predeclaredConstant, + "nil": predeclaredConstant, + + "append": predeclaredFunction, + "cap": predeclaredFunction, + "close": predeclaredFunction, + "complex": predeclaredFunction, + "copy": predeclaredFunction, + "delete": predeclaredFunction, + "imag": predeclaredFunction, + "len": predeclaredFunction, + "make": predeclaredFunction, + "new": predeclaredFunction, + "panic": predeclaredFunction, + "print": predeclaredFunction, + "println": predeclaredFunction, + "real": predeclaredFunction, + "recover": predeclaredFunction, +} + +const ( + ExportLinkAnnotation AnnotationKind = iota + AnchorAnnotation + CommentAnnotation + PackageLinkAnnotation + BuiltinAnnotation +) + +// annotationVisitor collects annotations. +type annotationVisitor struct { + annotations []Annotation +} + +func (v *annotationVisitor) add(kind AnnotationKind, importPath string) { + v.annotations = append(v.annotations, Annotation{Kind: kind, ImportPath: importPath}) +} + +func (v *annotationVisitor) ignoreName() { + v.add(-1, "") +} + +func (v *annotationVisitor) Visit(n ast.Node) ast.Visitor { + switch n := n.(type) { + case *ast.TypeSpec: + v.ignoreName() + ast.Walk(v, n.Type) + case *ast.FuncDecl: + if n.Recv != nil { + ast.Walk(v, n.Recv) + } + v.ignoreName() + ast.Walk(v, n.Type) + case *ast.Field: + for _ = range n.Names { + v.ignoreName() + } + ast.Walk(v, n.Type) + case *ast.ValueSpec: + for _ = range n.Names { + v.add(AnchorAnnotation, "") + } + if n.Type != nil { + ast.Walk(v, n.Type) + } + for _, x := range n.Values { + ast.Walk(v, x) + } + case *ast.Ident: + switch { + case n.Obj == nil && predeclared[n.Name] != notPredeclared: + v.add(BuiltinAnnotation, "") + case n.Obj != nil && ast.IsExported(n.Name): + v.add(ExportLinkAnnotation, "") + default: + v.ignoreName() + } + case *ast.SelectorExpr: + if x, _ := n.X.(*ast.Ident); x != nil { + if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg { + if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil { + if path, err := strconv.Unquote(spec.Path.Value); err == nil { + v.add(PackageLinkAnnotation, path) + if path == "C" { + v.ignoreName() + } else { + v.add(ExportLinkAnnotation, path) + } + return nil + } + } + } + } + ast.Walk(v, n.X) + v.ignoreName() + default: + return v + } + return nil +} + +func printDecl(decl ast.Node, fset *token.FileSet, buf []byte) (Code, []byte) { + v := &annotationVisitor{} + ast.Walk(v, decl) + + buf = buf[:0] + err := (&printer.Config{Mode: printer.UseSpaces, Tabwidth: 4}).Fprint(sliceWriter{&buf}, fset, decl) + if err != nil { + return Code{Text: err.Error()}, buf + } + + var annotations []Annotation + var s scanner.Scanner + fset = token.NewFileSet() + file := fset.AddFile("", fset.Base(), len(buf)) + s.Init(file, buf, nil, scanner.ScanComments) +loop: + for { + pos, tok, lit := s.Scan() + switch tok { + case token.EOF: + break loop + case token.COMMENT: + p := file.Offset(pos) + e := p + len(lit) + if p > math.MaxInt16 || e > math.MaxInt16 { + break loop + } + annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int16(p), End: int16(e)}) + case token.IDENT: + if len(v.annotations) == 0 { + // Oops! + break loop + } + annotation := v.annotations[0] + v.annotations = v.annotations[1:] + if annotation.Kind == -1 { + continue + } + p := file.Offset(pos) + e := p + len(lit) + if p > math.MaxInt16 || e > math.MaxInt16 { + break loop + } + annotation.Pos = int16(p) + annotation.End = int16(e) + if len(annotations) > 0 && annotation.Kind == ExportLinkAnnotation { + prev := annotations[len(annotations)-1] + if prev.Kind == PackageLinkAnnotation && + prev.ImportPath == annotation.ImportPath && + prev.End+1 == annotation.Pos { + // merge with previous + annotation.Pos = prev.Pos + annotations[len(annotations)-1] = annotation + continue loop + } + } + annotations = append(annotations, annotation) + } + } + return Code{Text: string(buf), Annotations: annotations}, buf +} + +type AnnotationKind int16 + +type Annotation struct { + Pos, End int16 + Kind AnnotationKind + ImportPath string +} + +type Code struct { + Text string + Annotations []Annotation +} + +func commentAnnotations(src string) []Annotation { + var annotations []Annotation + var s scanner.Scanner + fset := token.NewFileSet() + file := fset.AddFile("", fset.Base(), len(src)) + s.Init(file, []byte(src), nil, scanner.ScanComments) + for { + pos, tok, lit := s.Scan() + switch tok { + case token.EOF: + return annotations + case token.COMMENT: + p := file.Offset(pos) + e := p + len(lit) + if p > math.MaxInt16 || e > math.MaxInt16 { + return annotations + } + annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int16(p), End: int16(e)}) + } + } + return nil +} + +type sliceWriter struct{ p *[]byte } + +func (w sliceWriter) Write(p []byte) (int, error) { + *w.p = append(*w.p, p...) + return len(p), nil +} diff --git a/run.go b/run.go index f9ba02e..a386e42 100644 --- a/run.go +++ b/run.go @@ -38,11 +38,17 @@ var appname string var conf struct { // Indicates whether execute "go install" before "go build". GoInstall bool `json:"go_install"` + DirStruct struct { Controllers string Models string + Others []string // Other directories. } `json:"dir_structure"` - Files []string + + MainFiles struct { + Main string `json:"main.go"` + Others []string // Others files of package main. + } `json:"main_files"` } func runApp(cmd *Command, args []string) { @@ -60,8 +66,10 @@ func runApp(cmd *Command, args []string) { var paths []string paths = append(paths, path.Join(crupath, conf.DirStruct.Controllers), - path.Join(crupath, conf.DirStruct.Models)) - paths = append(paths, conf.Files...) + path.Join(crupath, conf.DirStruct.Models), + path.Join(crupath, conf.MainFiles.Main)) + paths = append(paths, conf.DirStruct.Others...) + paths = append(paths, conf.MainFiles.Others...) NewWatcher(paths) appname = args[0] @@ -94,5 +102,8 @@ func loadConfig() error { if len(conf.DirStruct.Models) == 0 { conf.DirStruct.Models = "models" } + if len(conf.MainFiles.Main) == 0 { + conf.MainFiles.Main = "main.go" + } return nil } diff --git a/testdata/router/router.go b/testdata/router/router.go new file mode 100644 index 0000000..beb8ba2 --- /dev/null +++ b/testdata/router/router.go @@ -0,0 +1,28 @@ +package router + +import ( + "github.com/astaxie/beego" +) + +type Router struct { + beego.Controller +} + +func (this *Router) Get() { + +} + +func (this *Router) Post() { + +} + +type Controller struct { +} + +func (this *Controller) Put() { + +} + +func (this *Controller) Delete() { + +} From bf5f0baed749a5e295b59b1cd7ef8e63116720ad Mon Sep 17 00:00:00 2001 From: astaxie Date: Tue, 30 Jul 2013 15:23:14 +0800 Subject: [PATCH 11/30] only watch go file's modify --- watch.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/watch.go b/watch.go index 98430d2..48881b3 100644 --- a/watch.go +++ b/watch.go @@ -33,6 +33,9 @@ func NewWatcher(paths []string) { if checkTMPFile(e.Name) { continue } + if !checkIsGoFile(e.Name) { + continue + } if t, ok := eventTime[e.Name]; ok { // if 500ms change many times, then ignore it. @@ -135,3 +138,11 @@ func checkTMPFile(name string) bool { } return false } + +// checkIsGoFile return true if the name is HasSuffix go +func checkIsGoFile(name string) bool { + if strings.HasSuffix(name, ".go") { + return true + } + return false +} From 859c694ce7f4ef3c078fcc18f9f8b2a98b2edd2e Mon Sep 17 00:00:00 2001 From: astaxie Date: Tue, 30 Jul 2013 15:35:39 +0800 Subject: [PATCH 12/30] can't read bee.json from project so it always err --- bee.json | 12 ------------ run.go | 35 ++++++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 21 deletions(-) delete mode 100644 bee.json diff --git a/bee.json b/bee.json deleted file mode 100644 index 8b21388..0000000 --- a/bee.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "go_install": false, - "dir_structure":{ - "controllers": "", - "models": "", - "others": [] - }, - "main_files":{ - "main.go": "", - "others": [] - } -} \ No newline at end of file diff --git a/run.go b/run.go index a386e42..eeb23cb 100644 --- a/run.go +++ b/run.go @@ -30,6 +30,21 @@ when the file has changed bee will auto go build and restart the app `, } +var defaultJson = ` +{ + "go_install": false, + "dir_structure":{ + "controllers": "", + "models": "", + "others": [] + }, + "main_files":{ + "main.go": "", + "others": [] + } +} +` + func init() { cmdRun.Run = runApp } @@ -85,16 +100,18 @@ func loadConfig() error { f, err := os.Open("bee.json") if err != nil { // Use default. - return nil + err = json.Unmarshal([]byte(defaultJson), &conf) + if err != nil { + return err + } + } else { + defer f.Close() + d := json.NewDecoder(f) + err = d.Decode(&conf) + if err != nil { + return err + } } - defer f.Close() - - d := json.NewDecoder(f) - err = d.Decode(&conf) - if err != nil { - return err - } - // Set variables. if len(conf.DirStruct.Controllers) == 0 { conf.DirStruct.Controllers = "controllers" From 8cbca4826e0f91b88acfa9f95e16812bd9b7ab67 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 31 Jul 2013 14:44:56 +0800 Subject: [PATCH 13/30] Watch current directory and ignore non-go files. --- run.go | 4 +++- watch.go | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/run.go b/run.go index eeb23cb..a5cace4 100644 --- a/run.go +++ b/run.go @@ -82,7 +82,9 @@ func runApp(cmd *Command, args []string) { paths = append(paths, path.Join(crupath, conf.DirStruct.Controllers), path.Join(crupath, conf.DirStruct.Models), - path.Join(crupath, conf.MainFiles.Main)) + path.Join(crupath, "./")) // Current path. + // Because monitor files has some issues, we watch current directory + // and ignore non-go files. paths = append(paths, conf.DirStruct.Others...) paths = append(paths, conf.MainFiles.Others...) diff --git a/watch.go b/watch.go index 48881b3..6207e05 100644 --- a/watch.go +++ b/watch.go @@ -139,7 +139,7 @@ func checkTMPFile(name string) bool { return false } -// checkIsGoFile return true if the name is HasSuffix go +// checkIsGoFile returns true if the name HasSuffix ".go". func checkIsGoFile(name string) bool { if strings.HasSuffix(name, ".go") { return true From 22db382cb877daa10866699e60fb845391001016 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 8 Aug 2013 06:41:00 +0800 Subject: [PATCH 14/30] Update --- run.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.go b/run.go index a5cace4..4be08de 100644 --- a/run.go +++ b/run.go @@ -98,7 +98,6 @@ func runApp(cmd *Command, args []string) { // loadConfig loads customized configuration. func loadConfig() error { - fmt.Println("[INFO] Detect bee.json") f, err := os.Open("bee.json") if err != nil { // Use default. @@ -108,6 +107,7 @@ func loadConfig() error { } } else { defer f.Close() + fmt.Println("[INFO] Detected bee.json") d := json.NewDecoder(f) err = d.Decode(&conf) if err != nil { From 89acd00955da73bb5c89ab17b2b75761183967ad Mon Sep 17 00:00:00 2001 From: astaxie Date: Fri, 9 Aug 2013 17:49:14 +0800 Subject: [PATCH 15/30] fix linux cpu 100% --- run.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/run.go b/run.go index 4be08de..cc18fa0 100644 --- a/run.go +++ b/run.go @@ -67,6 +67,7 @@ var conf struct { } func runApp(cmd *Command, args []string) { + exit := make(chan bool) if len(args) != 1 { fmt.Println("[ERRO] Argument [appname] is missing") os.Exit(2) @@ -92,7 +93,10 @@ func runApp(cmd *Command, args []string) { appname = args[0] Autobuild() for { - runtime.Gosched() + select { + case <-exit: + runtime.Goexit() + } } } From ea43654872f022102caab0c649d36b70a052c967 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 9 Aug 2013 22:40:46 +0800 Subject: [PATCH 16/30] Colorful log print --- new.go | 12 +++++----- run.go | 7 +++--- util.go | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- watch.go | 14 ++++++------ 4 files changed, 81 insertions(+), 21 deletions(-) diff --git a/new.go b/new.go index 63ee0d9..8c5ddd2 100644 --- a/new.go +++ b/new.go @@ -40,15 +40,15 @@ func init() { func createApp(cmd *Command, args []string) { curpath, _ := os.Getwd() if len(args) != 1 { - fmt.Println("[ERRO] Argument [appname] is missing") + colorLog("[ERRO] Argument [appname] is missing\n") os.Exit(2) } gopath := os.Getenv("GOPATH") Debugf("gopath:%s", gopath) if gopath == "" { - fmt.Printf("[ERRO] $GOPATH not found\n") - fmt.Printf("[HINT] Set $GOPATH in your environment vairables\n") + colorLog("[ERRO] $GOPATH not found\n") + colorLog("[HINT] Set $GOPATH in your environment vairables\n") os.Exit(2) } haspath := false @@ -66,8 +66,8 @@ func createApp(cmd *Command, args []string) { } if !haspath { - fmt.Printf("[ERRO] Unable to create an application outside of $GOPATH(%s)\n", gopath) - fmt.Printf("[HINT] Change your work directory by `cd $GOPATH%ssrc`\n", string(path.Separator)) + colorLog("[ERRO] Unable to create an application outside of $GOPATH(%s)\n", gopath) + colorLog("[HINT] Change your work directory by `cd ($GOPATH%ssrc)`\n", string(path.Separator)) os.Exit(2) } @@ -110,7 +110,7 @@ func createApp(cmd *Command, args []string) { 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)), string(path.Separator)), -1)) - fmt.Println("[SUCC] New application successfully created!") + colorLog("[SUCC] New application successfully created!\n") } var appconf = `appname = {{.Appname}} diff --git a/run.go b/run.go index cc18fa0..503abf3 100644 --- a/run.go +++ b/run.go @@ -2,7 +2,6 @@ package main import ( "encoding/json" - "fmt" "os" path "path/filepath" "runtime" @@ -69,7 +68,7 @@ var conf struct { func runApp(cmd *Command, args []string) { exit := make(chan bool) if len(args) != 1 { - fmt.Println("[ERRO] Argument [appname] is missing") + colorLog("[ERRO] Argument [appname] is missing\n") os.Exit(2) } crupath, _ := os.Getwd() @@ -77,7 +76,7 @@ func runApp(cmd *Command, args []string) { err := loadConfig() if err != nil { - fmt.Println("[ERRO] Fail to parse bee.json:", err) + colorLog("[ERRO] Fail to parse bee.json[ %s ]", err) } var paths []string paths = append(paths, @@ -111,7 +110,7 @@ func loadConfig() error { } } else { defer f.Close() - fmt.Println("[INFO] Detected bee.json") + colorLog("[INFO] Detected bee.json\n") d := json.NewDecoder(f) err = d.Decode(&conf) if err != nil { diff --git a/util.go b/util.go index f8b7e13..026d8ed 100644 --- a/util.go +++ b/util.go @@ -1,9 +1,12 @@ package main -import "fmt" -import "os" -import "runtime" -import "path/filepath" +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" +) // Go is a basic promise implementation: it wraps calls a function in a goroutine // and returns a channel which will later return the function's return value. @@ -28,3 +31,61 @@ func Debugf(format string, a ...interface{}) { fmt.Fprintf(os.Stderr, fmt.Sprintf("[debug] %s:%d %s\n", file, line, format), a...) } } + +const ( + Gray = uint8(iota + 90) + Red + Green + Yellow + Blue + Magenta + //NRed = uint8(31) // Normal + EndColor = "\033[0m" +) + +// colorLog colors log and print to stdout. +// Log format: [] [ error ]. +// Level: ERRO -> red; WARN -> Magenta; SUCC -> green; others -> default. +// Content: default; path: yellow; error -> red. +// Errors have to surrounded by "[ " and " ]"(space). +func colorLog(format string, a ...interface{}) { + log := fmt.Sprintf(format, a...) + if runtime.GOOS != "windows" { + var clog string + + // Level. + i := strings.Index(log, "]") + if log[0] == '[' && i > -1 { + clog += "[" + getColorLevel(log[1:i]) + "]" + } + + log = log[i+1:] + + // Error. + log = strings.Replace(log, "[ ", fmt.Sprintf("[ \033[%dm", Red), -1) + log = strings.Replace(log, " ]", EndColor+" ]", -1) + + // Path. + log = strings.Replace(log, "(", fmt.Sprintf("(\033[%dm", Yellow), -1) + log = strings.Replace(log, ")", EndColor+")", -1) + + log = clog + log + } + + fmt.Print(log) +} + +// getColorLevel returns colored level string by given level. +func getColorLevel(level string) string { + level = strings.ToUpper(level) + switch level { + case "ERRO": + return fmt.Sprintf("\033[%dm%s\033[0m", Red, level) + case "WARN": + return fmt.Sprintf("\033[%dm%s\033[0m", Magenta, level) + case "SUCC": + return fmt.Sprintf("\033[%dm%s\033[0m", Green, level) + default: + return level + } +} diff --git a/watch.go b/watch.go index 6207e05..1ce8d64 100644 --- a/watch.go +++ b/watch.go @@ -41,14 +41,14 @@ func NewWatcher(paths []string) { // if 500ms change many times, then ignore it. // for liteide often gofmt code after save. if t.Add(time.Millisecond * 500).After(time.Now()) { - fmt.Println("[SKIP]", e.String()) + colorLog("[SKIP] %s\n", e.String()) isbuild = false } } eventTime[e.Name] = time.Now() if isbuild { - fmt.Println("[EVEN]", e) + colorLog("[EVEN] %s\n", e) go Autobuild() } case err := <-watcher.Error: @@ -57,7 +57,7 @@ func NewWatcher(paths []string) { } }() - fmt.Println("[INFO] Initializing watcher...") + colorLog("[INFO] Initializing watcher...\n") for _, path := range paths { fmt.Println(path) err = watcher.Watch(path) @@ -72,7 +72,7 @@ func Autobuild() { state.Lock() defer state.Unlock() - fmt.Println("[INFO] Start building...") + colorLog("[INFO] Start building...\n") path, _ := os.Getwd() os.Chdir(path) @@ -94,10 +94,10 @@ func Autobuild() { } if err != nil { - fmt.Println("[ERRO] ============== Build failed ===================") + colorLog("[ERRO] ============== Build failed ===================\n") return } - fmt.Println("[SUCC] Build was successful") + colorLog("[SUCC] Build was successful\n") Restart(appname) } @@ -119,7 +119,7 @@ func Restart(appname string) { } func Start(appname string) { - fmt.Println("[INFO] Restarting", appname) + colorLog("[INFO] Restarting %s ...\n", appname) if strings.Index(appname, "./") == -1 { appname = "./" + appname } From f321e15db8ba7d5ed3f86999587edf6836ec97ec Mon Sep 17 00:00:00 2001 From: Philip Nelson Date: Sun, 11 Aug 2013 17:43:00 -0700 Subject: [PATCH 17/30] Go docs advise to use strings.HasPrefix. --- new.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new.go b/new.go index 8c5ddd2..da328e5 100644 --- a/new.go +++ b/new.go @@ -58,7 +58,7 @@ func createApp(cmd *Command, args []string) { for _, wg := range wgopath { wg = path.Join(wg, "src") - if path.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) { + if strings.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) { haspath = true appsrcpath = wg break From 61ed8f285b21772b1f875339e99cfe874134ecca Mon Sep 17 00:00:00 2001 From: Philip Nelson Date: Sun, 11 Aug 2013 21:38:57 -0700 Subject: [PATCH 18/30] Evaluate symlinks before comparing path. --- new.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/new.go b/new.go index da328e5..b4ed4ca 100644 --- a/new.go +++ b/new.go @@ -56,7 +56,7 @@ func createApp(cmd *Command, args []string) { wgopath := path.SplitList(gopath) for _, wg := range wgopath { - wg = path.Join(wg, "src") + wg, _ = path.EvalSymlinks(path.Join(wg, "src")) if strings.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) { haspath = true From 772e5676f75efeef7fc1f73081c9834fa482aa88 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 15 Aug 2013 12:51:26 +0800 Subject: [PATCH 19/30] Fixed bug: repeat build in Mac OS, change to check file ModTime insetad of event time --- watch.go | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/watch.go b/watch.go index 1ce8d64..cba403a 100644 --- a/watch.go +++ b/watch.go @@ -14,7 +14,7 @@ import ( var ( cmd *exec.Cmd state sync.Mutex - eventTime = make(map[string]time.Time) + eventTime = make(map[string]int64) ) func NewWatcher(paths []string) { @@ -37,15 +37,23 @@ func NewWatcher(paths []string) { continue } - if t, ok := eventTime[e.Name]; ok { - // if 500ms change many times, then ignore it. - // for liteide often gofmt code after save. - if t.Add(time.Millisecond * 500).After(time.Now()) { - colorLog("[SKIP] %s\n", e.String()) - isbuild = false - } + mt := getFileModTime(e.Name) + if t := eventTime[e.Name]; mt == t { + colorLog("[SKIP] %s\n", e.String()) + isbuild = false } - eventTime[e.Name] = time.Now() + + // if t, ok := eventTime[e.Name]; ok { + // // if 500ms change many times, then ignore it. + // // for liteide often gofmt code after save. + // if t.Add(time.Millisecond * 500).After(time.Now()) { + // colorLog("[SKIP] %s\n", e.String()) + // isbuild = false + // } + // } + + eventTime[e.Name] = mt + fmt.Println(mt) if isbuild { colorLog("[EVEN] %s\n", e) @@ -68,6 +76,23 @@ func NewWatcher(paths []string) { } +// getFileModTime retuens unix timestamp of `os.File.ModTime` by given path. +func getFileModTime(path string) int64 { + f, err := os.Open(path) + if err != nil { + colorLog("[ERRO] Fail to open file[ %s ]", err) + return time.Now().Unix() + } + + fi, err := f.Stat() + if err != nil { + colorLog("[ERRO] Fail to get file information[ %s ]", err) + return time.Now().Unix() + } + + return fi.ModTime().Unix() +} + func Autobuild() { state.Lock() defer state.Unlock() From bf33c2b05c3daa979fa96f924569fbea9a8100e1 Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 15 Aug 2013 12:51:48 +0800 Subject: [PATCH 20/30] Fixed bug: repeat build in Mac OS, change to check file ModTime insetad of event time --- watch.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/watch.go b/watch.go index cba403a..ece85da 100644 --- a/watch.go +++ b/watch.go @@ -43,15 +43,6 @@ func NewWatcher(paths []string) { isbuild = false } - // if t, ok := eventTime[e.Name]; ok { - // // if 500ms change many times, then ignore it. - // // for liteide often gofmt code after save. - // if t.Add(time.Millisecond * 500).After(time.Now()) { - // colorLog("[SKIP] %s\n", e.String()) - // isbuild = false - // } - // } - eventTime[e.Name] = mt fmt.Println(mt) From 5486f6ee5515280be7bcdce7f861b444da65b50a Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 15 Aug 2013 12:52:32 +0800 Subject: [PATCH 21/30] Fixed bug: repeat build in Mac OS, change to check file ModTime insetad of event time --- watch.go | 1 + 1 file changed, 1 insertion(+) diff --git a/watch.go b/watch.go index ece85da..7bf9c3e 100644 --- a/watch.go +++ b/watch.go @@ -74,6 +74,7 @@ func getFileModTime(path string) int64 { colorLog("[ERRO] Fail to open file[ %s ]", err) return time.Now().Unix() } + defer f.Close() fi, err := f.Stat() if err != nil { From a6840ebafde8defa8c1bf7ec0022625baa19962a Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 15 Aug 2013 12:53:07 +0800 Subject: [PATCH 22/30] Fixed bug: repeat build in Mac OS, change to check file ModTime insetad of event time --- watch.go | 1 - 1 file changed, 1 deletion(-) diff --git a/watch.go b/watch.go index 7bf9c3e..b640c6b 100644 --- a/watch.go +++ b/watch.go @@ -44,7 +44,6 @@ func NewWatcher(paths []string) { } eventTime[e.Name] = mt - fmt.Println(mt) if isbuild { colorLog("[EVEN] %s\n", e) From 055609f64dd526fce54d8359d80531765e8a8a9d Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 15 Aug 2013 15:24:23 +0800 Subject: [PATCH 23/30] Update color ouput --- .gitignore | 4 ++++ run.go | 3 ++- util.go | 14 ++++++++++---- watch.go | 10 ++++++---- 4 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..418384a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +bee +*.exe +*.exe~ diff --git a/run.go b/run.go index 503abf3..4fb3c97 100644 --- a/run.go +++ b/run.go @@ -68,7 +68,8 @@ var conf struct { func runApp(cmd *Command, args []string) { exit := make(chan bool) if len(args) != 1 { - colorLog("[ERRO] Argument [appname] is missing\n") + colorLog("[ERRO] Cannot start running[ %s ]\n", + "argument 'appname' is missing") os.Exit(2) } crupath, _ := os.Getwd() diff --git a/util.go b/util.go index 026d8ed..2846b97 100644 --- a/util.go +++ b/util.go @@ -62,12 +62,16 @@ func colorLog(format string, a ...interface{}) { log = log[i+1:] // Error. - log = strings.Replace(log, "[ ", fmt.Sprintf("[ \033[%dm", Red), -1) - log = strings.Replace(log, " ]", EndColor+" ]", -1) + log = strings.Replace(log, "[ ", fmt.Sprintf("[\033[%dm", Red), -1) + log = strings.Replace(log, " ]", EndColor+"]", -1) // Path. - log = strings.Replace(log, "(", fmt.Sprintf("(\033[%dm", Yellow), -1) - log = strings.Replace(log, ")", EndColor+")", -1) + log = strings.Replace(log, "( ", fmt.Sprintf("(\033[%dm", Yellow), -1) + log = strings.Replace(log, " )", EndColor+")", -1) + + // Highlights. + log = strings.Replace(log, "# ", fmt.Sprintf("\033[%dm", Gray), -1) + log = strings.Replace(log, " #", EndColor, -1) log = clog + log } @@ -79,6 +83,8 @@ func colorLog(format string, a ...interface{}) { func getColorLevel(level string) string { level = strings.ToUpper(level) switch level { + case "TRAC": + return fmt.Sprintf("\033[%dm%s\033[0m", Blue, level) case "ERRO": return fmt.Sprintf("\033[%dm%s\033[0m", Red, level) case "WARN": diff --git a/watch.go b/watch.go index b640c6b..9f05e53 100644 --- a/watch.go +++ b/watch.go @@ -20,7 +20,8 @@ var ( func NewWatcher(paths []string) { watcher, err := fsnotify.NewWatcher() if err != nil { - log.Fatal(err) + colorLog("[ERRO] Fail to create new Watcher[ %s ]\n", err) + os.Exit(2) } go func() { @@ -39,7 +40,7 @@ func NewWatcher(paths []string) { mt := getFileModTime(e.Name) if t := eventTime[e.Name]; mt == t { - colorLog("[SKIP] %s\n", e.String()) + colorLog("[SKIP] # %s #\n", e.String()) isbuild = false } @@ -57,10 +58,11 @@ func NewWatcher(paths []string) { colorLog("[INFO] Initializing watcher...\n") for _, path := range paths { - fmt.Println(path) + colorLog("[TRAC] Directory( %s )\n", path) err = watcher.Watch(path) if err != nil { - log.Fatal(err) + colorLog("[ERRO] Fail to watch directory[ %s ]\n", err) + os.Exit(2) } } From 916e7015809b7cbf08e244e5cc5f5aca07abfd0a Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 19 Aug 2013 10:27:44 +0800 Subject: [PATCH 24/30] fix post data format --- apiapp.go | 506 +++++++++++++++++++++++++++--------------------------- 1 file changed, 253 insertions(+), 253 deletions(-) diff --git a/apiapp.go b/apiapp.go index d04734f..705b1a0 100644 --- a/apiapp.go +++ b/apiapp.go @@ -1,253 +1,253 @@ -package main - -import ( - "fmt" - "os" - path "path/filepath" - "strings" -) - -var cmdApiapp = &Command{ - // CustomFlags: true, - UsageLine: "api [appname]", - Short: "create an api application base on beego framework", - Long: ` -create an api application base on beego framework - -In the current path, will create a folder named [appname] - -In the appname folder has the follow struct: - - ├── conf - │   └── app.conf - ├── controllers - │   └── default.go - ├── main.go - └── models - └── object.go - -`, -} - -var apiconf = ` -appname = {{.Appname}} -httpport = 8080 -runmode = dev -autorender = false -copyrequestbody = true -` -var apiMaingo = `package main - -import ( - "github.com/astaxie/beego" - "{{.Appname}}/controllers" -) - -// Objects - -// URL HTTP Verb Functionality -// /object POST Creating Objects -// /object/ GET Retrieving Objects -// /object/ PUT Updating Objects -// /object GET Queries -// /object/ DELETE Deleting Objects - -func main() { - beego.RESTRouter("/object", &controllers.ObejctController{}) - beego.Run() -} -` -var apiModels = `package models - -import ( - "errors" - "strconv" - "time" -) - -var ( - Objects map[string]*Object -) - -type Object struct { - ObjectId string - Score int64 - PlayerName string -} - -func init() { - Objects = make(map[string]*Object) - Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"} - Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"} -} - -func AddOne(object Object) (ObjectId string) { - object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10) - Objects[object.ObjectId] = &object - return object.ObjectId -} - -func GetOne(ObjectId string) (object *Object, err error) { - if v, ok := Objects[ObjectId]; ok { - return v, nil - } - return nil, errors.New("ObjectId Not Exist") -} - -func GetAll() map[string]*Object { - return Objects -} - -func Update(ObjectId string, Score int64) (err error) { - if v, ok := Objects[ObjectId]; ok { - v.Score = Score - return nil - } - return errors.New("ObjectId Not Exist") -} - -func Delete(ObjectId string) { - delete(Objects, ObjectId) -} -` - -var apiControllers = `package controllers - -import ( - "encoding/json" - "github.com/astaxie/beego" - "{{.Appname}}/models" -) - -type ResponseInfo struct { -} - -type ObejctController struct { - beego.Controller -} - -func (this *ObejctController) Post() { - var ob models.Object - json.Unmarshal(this.Ctx.RequestBody, &ob) - objectid := models.AddOne(ob) - this.Data["json"] = "{\"ObjectId\":\"" + objectid + "\"}" - this.ServeJson() -} - -func (this *ObejctController) Get() { - objectId := this.Ctx.Params[":objectId"] - if objectId != "" { - ob, err := models.GetOne(objectId) - if err != nil { - this.Data["json"] = err - } else { - this.Data["json"] = ob - } - } else { - obs := models.GetAll() - this.Data["json"] = obs - } - this.ServeJson() -} - -func (this *ObejctController) Put() { - objectId := this.Ctx.Params[":objectId"] - var ob models.Object - json.Unmarshal(this.Ctx.RequestBody, &ob) - - err := models.Update(objectId, ob.Score) - if err != nil { - this.Data["json"] = err - } else { - this.Data["json"] = "update success!" - } - this.ServeJson() -} - -func (this *ObejctController) Delete() { - objectId := this.Ctx.Params[":objectId"] - models.Delete(objectId) - this.Data["json"] = "delete success!" - this.ServeJson() -} -` - -func init() { - cmdApiapp.Run = createapi -} - -func createapi(cmd *Command, args []string) { - if len(args) != 1 { - fmt.Println("error args") - os.Exit(2) - } - apppath, packpath, err := checkEnv(args[0]) - if err != nil { - fmt.Println(err) - os.Exit(2) - } - 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, "models"), 0755) - fmt.Println("create models:", path.Join(apppath, "models")) - - 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)) - - fmt.Println("create controllers default.go:", path.Join(apppath, "controllers", "default.go")) - writetofile(path.Join(apppath, "controllers", "default.go"), - strings.Replace(apiControllers, "{{.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("create main.go:", path.Join(apppath, "main.go")) - writetofile(path.Join(apppath, "main.go"), - strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1)) -} - -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 == "" { - err = fmt.Errorf("you should set GOPATH in the env") - return - } - - appsrcpath := "" - haspath := false - wgopath := path.SplitList(gopath) - for _, wg := range wgopath { - wg = path.Join(wg, "src") - - if path.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) - - if _, e := os.Stat(apppath); os.IsNotExist(e) == false { - err = fmt.Errorf("path `%s` exists, can not create app without remove it\n", apppath) - return - } - packpath = strings.Join(strings.Split(apppath[len(appsrcpath)+1:], string(path.Separator)), "/") - return -} +package main + +import ( + "fmt" + "os" + path "path/filepath" + "strings" +) + +var cmdApiapp = &Command{ + // CustomFlags: true, + UsageLine: "api [appname]", + Short: "create an api application base on beego framework", + Long: ` +create an api application base on beego framework + +In the current path, will create a folder named [appname] + +In the appname folder has the follow struct: + + ├── conf + │ └── app.conf + ├── controllers + │ └── default.go + ├── main.go + └── models + └── object.go + +`, +} + +var apiconf = ` +appname = {{.Appname}} +httpport = 8080 +runmode = dev +autorender = false +copyrequestbody = true +` +var apiMaingo = `package main + +import ( + "github.com/astaxie/beego" + "{{.Appname}}/controllers" +) + +// Objects + +// URL HTTP Verb Functionality +// /object POST Creating Objects +// /object/ GET Retrieving Objects +// /object/ PUT Updating Objects +// /object GET Queries +// /object/ DELETE Deleting Objects + +func main() { + beego.RESTRouter("/object", &controllers.ObejctController{}) + beego.Run() +} +` +var apiModels = `package models + +import ( + "errors" + "strconv" + "time" +) + +var ( + Objects map[string]*Object +) + +type Object struct { + ObjectId string + Score int64 + PlayerName string +} + +func init() { + Objects = make(map[string]*Object) + Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"} + Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"} +} + +func AddOne(object Object) (ObjectId string) { + object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10) + Objects[object.ObjectId] = &object + return object.ObjectId +} + +func GetOne(ObjectId string) (object *Object, err error) { + if v, ok := Objects[ObjectId]; ok { + return v, nil + } + return nil, errors.New("ObjectId Not Exist") +} + +func GetAll() map[string]*Object { + return Objects +} + +func Update(ObjectId string, Score int64) (err error) { + if v, ok := Objects[ObjectId]; ok { + v.Score = Score + return nil + } + return errors.New("ObjectId Not Exist") +} + +func Delete(ObjectId string) { + delete(Objects, ObjectId) +} +` + +var apiControllers = `package controllers + +import ( + "encoding/json" + "github.com/astaxie/beego" + "{{.Appname}}/models" +) + +type ResponseInfo struct { +} + +type ObejctController struct { + beego.Controller +} + +func (this *ObejctController) Post() { + var ob models.Object + json.Unmarshal(this.Ctx.RequestBody, &ob) + objectid := models.AddOne(ob) + this.Data["json"] = map[string]string{"ObjectId": objectid} + this.ServeJson() +} + +func (this *ObejctController) Get() { + objectId := this.Ctx.Params[":objectId"] + if objectId != "" { + ob, err := models.GetOne(objectId) + if err != nil { + this.Data["json"] = err + } else { + this.Data["json"] = ob + } + } else { + obs := models.GetAll() + this.Data["json"] = obs + } + this.ServeJson() +} + +func (this *ObejctController) Put() { + objectId := this.Ctx.Params[":objectId"] + var ob models.Object + json.Unmarshal(this.Ctx.RequestBody, &ob) + + err := models.Update(objectId, ob.Score) + if err != nil { + this.Data["json"] = err + } else { + this.Data["json"] = "update success!" + } + this.ServeJson() +} + +func (this *ObejctController) Delete() { + objectId := this.Ctx.Params[":objectId"] + models.Delete(objectId) + this.Data["json"] = "delete success!" + this.ServeJson() +} +` + +func init() { + cmdApiapp.Run = createapi +} + +func createapi(cmd *Command, args []string) { + if len(args) != 1 { + fmt.Println("error args") + os.Exit(2) + } + apppath, packpath, err := checkEnv(args[0]) + if err != nil { + fmt.Println(err) + os.Exit(2) + } + 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, "models"), 0755) + fmt.Println("create models:", path.Join(apppath, "models")) + + 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)) + + fmt.Println("create controllers default.go:", path.Join(apppath, "controllers", "default.go")) + writetofile(path.Join(apppath, "controllers", "default.go"), + strings.Replace(apiControllers, "{{.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("create main.go:", path.Join(apppath, "main.go")) + writetofile(path.Join(apppath, "main.go"), + strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1)) +} + +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 == "" { + err = fmt.Errorf("you should set GOPATH in the env") + return + } + + appsrcpath := "" + haspath := false + wgopath := path.SplitList(gopath) + for _, wg := range wgopath { + wg = path.Join(wg, "src") + + if path.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) + + if _, e := os.Stat(apppath); os.IsNotExist(e) == false { + err = fmt.Errorf("path `%s` exists, can not create app without remove it\n", apppath) + return + } + packpath = strings.Join(strings.Split(apppath[len(appsrcpath)+1:], string(path.Separator)), "/") + return +} From 9ba4bbc1bc6ee42c208ddcef09bd37faf868653f Mon Sep 17 00:00:00 2001 From: fanngyuan Date: Thu, 22 Aug 2013 11:03:31 +0800 Subject: [PATCH 25/30] add test --- apiapp.go | 2 ++ test.go | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 test.go diff --git a/apiapp.go b/apiapp.go index 705b1a0..18b1a91 100644 --- a/apiapp.go +++ b/apiapp.go @@ -194,6 +194,8 @@ func createapi(cmd *Command, args []string) { fmt.Println("create controllers:", path.Join(apppath, "controllers")) os.Mkdir(path.Join(apppath, "models"), 0755) fmt.Println("create models:", path.Join(apppath, "models")) + 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"), diff --git a/test.go b/test.go new file mode 100644 index 0000000..56446b4 --- /dev/null +++ b/test.go @@ -0,0 +1,82 @@ +package main + +import ( + "os" + path "path/filepath" + "os/exec" + "time" + "bytes" +) + +var cmdTest = &Command{ + UsageLine: "test [appname]", + Short: "test the app", + Long: ``, +} + +func init() { + cmdTest.Run = testApp +} + +var started= make(chan bool) + +func testApp(cmd *Command, args []string) { + if len(args) != 1 { + colorLog("[ERRO] Cannot start running[ %s ]\n", + "argument 'appname' is missing") + os.Exit(2) + } + crupath, _ := os.Getwd() + Debugf("current path:%s\n", crupath) + + err := loadConfig() + if err != nil { + colorLog("[ERRO] Fail to parse bee.json[ %s ]", err) + } + var paths []string + paths = append(paths, + path.Join(crupath, conf.DirStruct.Controllers), + path.Join(crupath, conf.DirStruct.Models), + path.Join(crupath, "./")) // Current path. + // Because monitor files has some issues, we watch current directory + // and ignore non-go files. + paths = append(paths, conf.DirStruct.Others...) + paths = append(paths, conf.MainFiles.Others...) + + NewWatcher(paths) + appname = args[0] + Autobuild() + for { + select { + case <-started: + runTest() + Kill() + os.Exit(0) + } + } +} + +func runTest(){ + colorLog("[INFO] Start testing...\n") + time.Sleep(time.Second*5) + path, _ := os.Getwd() + os.Chdir(path+"/tests") + + var err error + icmd := exec.Command("go", "test") + var out,errbuffer bytes.Buffer + icmd.Stdout = &out + icmd.Stderr = &errbuffer + colorLog("[INFO] ============== Test Begin ===================\n") + err = icmd.Run() + colorLog(out.String()) + colorLog(errbuffer.String()) + colorLog("[INFO] ============== Test End ===================\n") + + if err != nil { + colorLog("[ERRO] ============== Test failed ===================\n") + colorLog("[ERRO] " ,err) + return + } + colorLog("[SUCC] Test finish\n") +} From d42aec07b4be3a7059209396878bd127c41e074c Mon Sep 17 00:00:00 2001 From: fanngyuan Date: Thu, 22 Aug 2013 12:19:45 +0800 Subject: [PATCH 26/30] =?UTF-8?q?=E5=88=9A=E6=89=8D=E6=BC=8F=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bee.go | 1 + watch.go | 1 + 2 files changed, 2 insertions(+) diff --git a/bee.go b/bee.go index 5450aea..e31c536 100644 --- a/bee.go +++ b/bee.go @@ -76,6 +76,7 @@ var commands = []*Command{ cmdPack, cmdApiapp, cmdRouter, + cmdTest, //cmdReStart, } diff --git a/watch.go b/watch.go index 9f05e53..34cd6a7 100644 --- a/watch.go +++ b/watch.go @@ -147,6 +147,7 @@ func Start(appname string) { cmd.Stderr = os.Stderr go cmd.Run() + started<-true } // checkTMPFile returns true if the event was for TMP files. From 90648d22cda427612025466ce7dc73363aab2f03 Mon Sep 17 00:00:00 2001 From: slene Date: Thu, 22 Aug 2013 14:54:02 +0800 Subject: [PATCH 27/30] avoid panic when len(log) == 0 in colorLog func --- util.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util.go b/util.go index 2846b97..6cafb46 100644 --- a/util.go +++ b/util.go @@ -50,6 +50,10 @@ const ( // Errors have to surrounded by "[ " and " ]"(space). func colorLog(format string, a ...interface{}) { log := fmt.Sprintf(format, a...) + if len(log) == 0 { + return + } + if runtime.GOOS != "windows" { var clog string From 285e130505144498fbbd5ff99210b2bb22e67e00 Mon Sep 17 00:00:00 2001 From: fanngyuan Date: Tue, 27 Aug 2013 22:35:48 +0800 Subject: [PATCH 28/30] add template --- apiapp.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/apiapp.go b/apiapp.go index 18b1a91..175e59f 100644 --- a/apiapp.go +++ b/apiapp.go @@ -54,6 +54,7 @@ import ( func main() { beego.RESTRouter("/object", &controllers.ObejctController{}) + beego.Router("/ping", &controllers.ObejctController{},"get:Ping") beego.Run() } ` @@ -170,8 +171,33 @@ func (this *ObejctController) Delete() { this.Data["json"] = "delete success!" this.ServeJson() } + +func (this *ObejctController) Ping() { + this.Ctx.WriteString("pong") +} + ` +var apiTests = `package tests + +import ( + "testing" + beetest "github.com/fanngyuan/beego/testing" + "io/ioutil" +) + +func TestHelloWorld(t *testing.T) { + request:=beetest.Get("/ping") + response,_:=request.Response() + defer response.Body.Close() + contents, _ := ioutil.ReadAll(response.Body) + if string(contents)!="pong"{ + t.Errorf("response sould be pong") + } +} + +` + func init() { cmdApiapp.Run = createapi } @@ -205,6 +231,10 @@ func createapi(cmd *Command, args []string) { writetofile(path.Join(apppath, "controllers", "default.go"), strings.Replace(apiControllers, "{{.Appname}}", packpath, -1)) + fmt.Println("create tests default.go:", path.Join(apppath, "tests", "default_test.go")) + writetofile(path.Join(apppath, "tests", "default_test.go"), + apiTests) + fmt.Println("create models object.go:", path.Join(apppath, "models", "object.go")) writetofile(path.Join(apppath, "models", "object.go"), apiModels) From f839552b8dbfe035907021b2dbfeba6987d00828 Mon Sep 17 00:00:00 2001 From: fanngyuan Date: Wed, 28 Aug 2013 11:04:12 +0800 Subject: [PATCH 29/30] fix bug --- apiapp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiapp.go b/apiapp.go index 175e59f..7ee4417 100644 --- a/apiapp.go +++ b/apiapp.go @@ -182,7 +182,7 @@ var apiTests = `package tests import ( "testing" - beetest "github.com/fanngyuan/beego/testing" + beetest "github.com/astaxie/beego/testing" "io/ioutil" ) From 550cf6cb716b6d71de45ddc9f22654d7366ebd9c Mon Sep 17 00:00:00 2001 From: astaxie Date: Wed, 11 Sep 2013 18:18:02 +0800 Subject: [PATCH 30/30] update apiapp --- apiapp.go | 514 +++++++++++++++++++++++++++--------------------------- 1 file changed, 257 insertions(+), 257 deletions(-) diff --git a/apiapp.go b/apiapp.go index 7ee4417..ef16306 100644 --- a/apiapp.go +++ b/apiapp.go @@ -1,183 +1,183 @@ -package main - -import ( - "fmt" - "os" - path "path/filepath" - "strings" -) - -var cmdApiapp = &Command{ - // CustomFlags: true, - UsageLine: "api [appname]", - Short: "create an api application base on beego framework", - Long: ` -create an api application base on beego framework - -In the current path, will create a folder named [appname] - -In the appname folder has the follow struct: - - ├── conf - │ └── app.conf - ├── controllers - │ └── default.go - ├── main.go - └── models - └── object.go - -`, -} - -var apiconf = ` -appname = {{.Appname}} -httpport = 8080 -runmode = dev -autorender = false -copyrequestbody = true -` -var apiMaingo = `package main - -import ( - "github.com/astaxie/beego" - "{{.Appname}}/controllers" -) - -// Objects - -// URL HTTP Verb Functionality -// /object POST Creating Objects -// /object/ GET Retrieving Objects -// /object/ PUT Updating Objects -// /object GET Queries -// /object/ DELETE Deleting Objects - -func main() { - beego.RESTRouter("/object", &controllers.ObejctController{}) +package main + +import ( + "fmt" + "os" + path "path/filepath" + "strings" +) + +var cmdApiapp = &Command{ + // CustomFlags: true, + UsageLine: "api [appname]", + Short: "create an api application base on beego framework", + Long: ` +create an api application base on beego framework + +In the current path, will create a folder named [appname] + +In the appname folder has the follow struct: + + ├── conf + │ └── app.conf + ├── controllers + │ └── default.go + ├── main.go + └── models + └── object.go + +`, +} + +var apiconf = ` +appname = {{.Appname}} +httpport = 8080 +runmode = dev +autorender = false +copyrequestbody = true +` +var apiMaingo = `package main + +import ( + "github.com/astaxie/beego" + "{{.Appname}}/controllers" +) + +// Objects + +// URL HTTP Verb Functionality +// /object POST Creating Objects +// /object/ GET Retrieving Objects +// /object/ PUT Updating Objects +// /object GET Queries +// /object/ DELETE Deleting Objects + +func main() { + beego.RESTRouter("/object", &controllers.ObejctController{}) beego.Router("/ping", &controllers.ObejctController{},"get:Ping") - beego.Run() -} -` -var apiModels = `package models - -import ( - "errors" - "strconv" - "time" -) - -var ( - Objects map[string]*Object -) - -type Object struct { - ObjectId string - Score int64 - PlayerName string -} - -func init() { - Objects = make(map[string]*Object) - Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"} - Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"} -} - -func AddOne(object Object) (ObjectId string) { - object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10) - Objects[object.ObjectId] = &object - return object.ObjectId -} - -func GetOne(ObjectId string) (object *Object, err error) { - if v, ok := Objects[ObjectId]; ok { - return v, nil - } - return nil, errors.New("ObjectId Not Exist") -} - -func GetAll() map[string]*Object { - return Objects -} - -func Update(ObjectId string, Score int64) (err error) { - if v, ok := Objects[ObjectId]; ok { - v.Score = Score - return nil - } - return errors.New("ObjectId Not Exist") -} - -func Delete(ObjectId string) { - delete(Objects, ObjectId) -} -` - -var apiControllers = `package controllers - -import ( - "encoding/json" - "github.com/astaxie/beego" - "{{.Appname}}/models" -) - -type ResponseInfo struct { -} - -type ObejctController struct { - beego.Controller -} - -func (this *ObejctController) Post() { - var ob models.Object - json.Unmarshal(this.Ctx.RequestBody, &ob) - objectid := models.AddOne(ob) - this.Data["json"] = map[string]string{"ObjectId": objectid} - this.ServeJson() -} - -func (this *ObejctController) Get() { - objectId := this.Ctx.Params[":objectId"] - if objectId != "" { - ob, err := models.GetOne(objectId) - if err != nil { - this.Data["json"] = err - } else { - this.Data["json"] = ob - } - } else { - obs := models.GetAll() - this.Data["json"] = obs - } - this.ServeJson() -} - -func (this *ObejctController) Put() { - objectId := this.Ctx.Params[":objectId"] - var ob models.Object - json.Unmarshal(this.Ctx.RequestBody, &ob) - - err := models.Update(objectId, ob.Score) - if err != nil { - this.Data["json"] = err - } else { - this.Data["json"] = "update success!" - } - this.ServeJson() -} - -func (this *ObejctController) Delete() { - objectId := this.Ctx.Params[":objectId"] - models.Delete(objectId) - this.Data["json"] = "delete success!" - this.ServeJson() -} + beego.Run() +} +` +var apiModels = `package models -func (this *ObejctController) Ping() { +import ( + "errors" + "strconv" + "time" +) + +var ( + Objects map[string]*Object +) + +type Object struct { + ObjectId string + Score int64 + PlayerName string +} + +func init() { + Objects = make(map[string]*Object) + Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"} + Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"} +} + +func AddOne(object Object) (ObjectId string) { + object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10) + Objects[object.ObjectId] = &object + return object.ObjectId +} + +func GetOne(ObjectId string) (object *Object, err error) { + if v, ok := Objects[ObjectId]; ok { + return v, nil + } + return nil, errors.New("ObjectId Not Exist") +} + +func GetAll() map[string]*Object { + return Objects +} + +func Update(ObjectId string, Score int64) (err error) { + if v, ok := Objects[ObjectId]; ok { + v.Score = Score + return nil + } + return errors.New("ObjectId Not Exist") +} + +func Delete(ObjectId string) { + delete(Objects, ObjectId) +} +` + +var apiControllers = `package controllers + +import ( + "encoding/json" + "github.com/astaxie/beego" + "{{.Appname}}/models" +) + +type ResponseInfo struct { +} + +type ObejctController struct { + beego.Controller +} + +func (this *ObejctController) Post() { + var ob models.Object + json.Unmarshal(this.Ctx.Input.RequestBody, &ob) + objectid := models.AddOne(ob) + this.Data["json"] = map[string]string{"ObjectId": objectid} + this.ServeJson() +} + +func (this *ObejctController) Get() { + objectId := this.Ctx.Params[":objectId"] + if objectId != "" { + ob, err := models.GetOne(objectId) + if err != nil { + this.Data["json"] = err + } else { + this.Data["json"] = ob + } + } else { + obs := models.GetAll() + this.Data["json"] = obs + } + this.ServeJson() +} + +func (this *ObejctController) Put() { + objectId := this.Ctx.Params[":objectId"] + var ob models.Object + json.Unmarshal(this.Ctx.Input.RequestBody, &ob) + + err := models.Update(objectId, ob.Score) + if err != nil { + this.Data["json"] = err + } else { + this.Data["json"] = "update success!" + } + this.ServeJson() +} + +func (this *ObejctController) Delete() { + objectId := this.Ctx.Input.Params[":objectId"] + models.Delete(objectId) + this.Data["json"] = "delete success!" + this.ServeJson() +} + +func (this *ObejctController) Ping() { this.Ctx.WriteString("pong") -} +} + +` -` - var apiTests = `package tests import ( @@ -198,88 +198,88 @@ func TestHelloWorld(t *testing.T) { ` -func init() { - cmdApiapp.Run = createapi -} - -func createapi(cmd *Command, args []string) { - if len(args) != 1 { - fmt.Println("error args") - os.Exit(2) - } - apppath, packpath, err := checkEnv(args[0]) - if err != nil { - fmt.Println(err) - os.Exit(2) - } - 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, "models"), 0755) - fmt.Println("create models:", path.Join(apppath, "models")) - 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)) - - fmt.Println("create controllers default.go:", path.Join(apppath, "controllers", "default.go")) - writetofile(path.Join(apppath, "controllers", "default.go"), - strings.Replace(apiControllers, "{{.Appname}}", packpath, -1)) - +func init() { + cmdApiapp.Run = createapi +} + +func createapi(cmd *Command, args []string) { + if len(args) != 1 { + fmt.Println("error args") + os.Exit(2) + } + apppath, packpath, err := checkEnv(args[0]) + if err != nil { + fmt.Println(err) + os.Exit(2) + } + 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, "models"), 0755) + fmt.Println("create models:", path.Join(apppath, "models")) + 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)) + + fmt.Println("create controllers default.go:", path.Join(apppath, "controllers", "default.go")) + writetofile(path.Join(apppath, "controllers", "default.go"), + strings.Replace(apiControllers, "{{.Appname}}", packpath, -1)) + fmt.Println("create tests default.go:", path.Join(apppath, "tests", "default_test.go")) writetofile(path.Join(apppath, "tests", "default_test.go"), apiTests) - fmt.Println("create models object.go:", path.Join(apppath, "models", "object.go")) - writetofile(path.Join(apppath, "models", "object.go"), apiModels) - - fmt.Println("create main.go:", path.Join(apppath, "main.go")) - writetofile(path.Join(apppath, "main.go"), - strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1)) -} - -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 == "" { - err = fmt.Errorf("you should set GOPATH in the env") - return - } - - appsrcpath := "" - haspath := false - wgopath := path.SplitList(gopath) - for _, wg := range wgopath { - wg = path.Join(wg, "src") - - if path.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) - - if _, e := os.Stat(apppath); os.IsNotExist(e) == false { - err = fmt.Errorf("path `%s` exists, can not create app without remove it\n", apppath) - return - } - packpath = strings.Join(strings.Split(apppath[len(appsrcpath)+1:], string(path.Separator)), "/") - return -} + fmt.Println("create models object.go:", path.Join(apppath, "models", "object.go")) + writetofile(path.Join(apppath, "models", "object.go"), apiModels) + + fmt.Println("create main.go:", path.Join(apppath, "main.go")) + writetofile(path.Join(apppath, "main.go"), + strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1)) +} + +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 == "" { + err = fmt.Errorf("you should set GOPATH in the env") + return + } + + appsrcpath := "" + haspath := false + wgopath := path.SplitList(gopath) + for _, wg := range wgopath { + wg = path.Join(wg, "src") + + if path.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) + + if _, e := os.Stat(apppath); os.IsNotExist(e) == false { + err = fmt.Errorf("path `%s` exists, can not create app without remove it\n", apppath) + return + } + packpath = strings.Join(strings.Split(apppath[len(appsrcpath)+1:], string(path.Separator)), "/") + return +}