diff --git a/createapp.go b/createapp.go
new file mode 100644
index 0000000..61b8d5e
--- /dev/null
+++ b/createapp.go
@@ -0,0 +1,163 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "path"
+ "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) {
+ crupath, _ := os.Getwd()
+ if len(args) != 1 {
+ fmt.Println("error args")
+ os.Exit(2)
+ }
+ gopath := os.Getenv("GOPATH")
+ if gopath == "" {
+ fmt.Println("you should set GOPATH in the env")
+ os.Exit(2)
+ }
+ haspath := false
+ if crupath != path.Join(gopath, "src") {
+ wgopath := strings.Split(gopath, ";")
+ if len(wgopath) >= 1 {
+ for _, wg := range wgopath {
+ wg = wg + `\src`
+ if crupath == wg {
+ haspath = true
+ break
+ }
+ }
+ }
+ if !haspath {
+ lgopath := strings.Split(gopath, ":")
+ if len(lgopath) >= 1 {
+ for _, wg := range lgopath {
+ if crupath == path.Join(wg, "src") {
+ haspath = true
+ break
+ }
+ }
+ }
+ }
+
+ } else {
+ haspath = true
+ }
+ if !haspath {
+ fmt.Println("can't create application outside of GOPATH")
+ fmt.Println("you first should `cd $GOPATH/src` then use create")
+ os.Exit(2)
+ }
+ apppath := path.Join(crupath, args[0])
+ os.Mkdir(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, "conf"), 0755)
+ fmt.Println("create models:", path.Join(apppath, "models"))
+ os.Mkdir(path.Join(apppath, "models"), 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"), "appname = "+args[0])
+
+ 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}}", args[0], -1))
+}
+
+var maingo = `package main
+
+import (
+ "{{.Appname}}/controllers"
+ "github.com/astaxie/beego"
+)
+
+func main() {
+ beego.BeeApp.RegisterController("/", &controllers.MainController{})
+ beego.BeeApp.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
new file mode 100644
index 0000000..bd309e9
--- /dev/null
+++ b/main.go
@@ -0,0 +1,160 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "html/template"
+ "io"
+ "log"
+ "os"
+ "strings"
+)
+
+type Command struct {
+ // Run runs the command.
+ // The args are the arguments after the command name.
+ Run func(cmd *Command, args []string)
+
+ // UsageLine is the one-line usage message.
+ // The first word in the line is taken to be the command name.
+ UsageLine string
+
+ // Short is the short description shown in the 'go help' output.
+ Short string
+
+ // Long is the long message shown in the 'go help ' output.
+ Long string
+
+ // Flag is a set of flags specific to this command.
+ Flag flag.FlagSet
+
+ // CustomFlags indicates that the command will do its own
+ // flag parsing.
+ CustomFlags bool
+}
+
+// Name returns the command's name: the first word in the usage line.
+func (c *Command) Name() string {
+ name := c.UsageLine
+ i := strings.Index(name, " ")
+ if i >= 0 {
+ name = name[:i]
+ }
+ return name
+}
+
+func (c *Command) Usage() {
+ fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
+ fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
+ os.Exit(2)
+}
+
+// Runnable reports whether the command can be run; otherwise
+// it is a documentation pseudo-command such as importpath.
+func (c *Command) Runnable() bool {
+ return c.Run != nil
+}
+
+var commands = []*Command{
+ cmdCreate,
+ cmdStart,
+ //cmdReStart,
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ log.SetFlags(0)
+
+ args := flag.Args()
+ if len(args) < 1 {
+ usage()
+ }
+
+ if args[0] == "help" {
+ help(args[1:])
+ return
+ }
+
+ for _, cmd := range commands {
+ if cmd.Name() == args[0] && cmd.Run != nil {
+ cmd.Flag.Usage = func() { cmd.Usage() }
+ if cmd.CustomFlags {
+ args = args[1:]
+ } else {
+ cmd.Flag.Parse(args[1:])
+ args = cmd.Flag.Args()
+ }
+ cmd.Run(cmd, args)
+ os.Exit(2)
+ return
+ }
+ }
+
+ fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0])
+ os.Exit(2)
+}
+
+var usageTemplate = `Bee is a tool for managing beego framework.
+
+Usage:
+
+ bee command [arguments]
+
+The commands are:
+{{range .}}{{if .Runnable}}
+ {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+
+Use "bee help [command]" for more information about a command.
+
+Additional help topics:
+{{range .}}{{if not .Runnable}}
+ {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+
+Use "bee help [topic]" for more information about that topic.
+
+`
+
+var helpTemplate = `{{if .Runnable}}usage: bee {{.UsageLine}}
+
+{{end}}{{.Long | trim}}
+`
+
+func usage() {
+ tmpl(os.Stdout, usageTemplate, commands)
+ os.Exit(2)
+}
+
+func tmpl(w io.Writer, text string, data interface{}) {
+ t := template.New("top")
+ t.Funcs(template.FuncMap{"trim": strings.TrimSpace})
+ template.Must(t.Parse(text))
+ if err := t.Execute(w, data); err != nil {
+ panic(err)
+ }
+}
+
+func help(args []string) {
+ if len(args) == 0 {
+ usage()
+ // not exit 2: succeeded at 'go help'.
+ return
+ }
+ if len(args) != 1 {
+ fmt.Fprintf(os.Stdout, "usage: bee help command\n\nToo many arguments given.\n")
+ os.Exit(2) // failed at 'bee help'
+ }
+
+ arg := args[0]
+
+ for _, cmd := range commands {
+ if cmd.Name() == arg {
+ tmpl(os.Stdout, helpTemplate, cmd)
+ // not exit 2: succeeded at 'go help cmd'.
+ return
+ }
+ }
+
+ fmt.Fprintf(os.Stdout, "Unknown help topic %#q. Run 'bee help'.\n", arg)
+ os.Exit(2) // failed at 'bee help cmd'
+}
diff --git a/start.go b/start.go
new file mode 100644
index 0000000..a63a16e
--- /dev/null
+++ b/start.go
@@ -0,0 +1,53 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "path"
+)
+
+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
+}
+
+func startapp(cmd *Command, args []string) {
+ if len(args) != 1 {
+ fmt.Println("error args")
+ os.Exit(2)
+ }
+ crupath, _ := os.Getwd()
+ var paths []string
+ paths = append(paths, path.Join(crupath, "controllers"), path.Join(crupath, "models"))
+ NewWatcher(paths)
+ go Start(args[0])
+ for {
+ select {
+ case <-restart:
+ go Start(args[0])
+ case <-builderror:
+ fmt.Println("build error:", builderror)
+ }
+ }
+}
diff --git a/watch.go b/watch.go
new file mode 100644
index 0000000..97a65f9
--- /dev/null
+++ b/watch.go
@@ -0,0 +1,120 @@
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "github.com/howeyc/fsnotify"
+ "io"
+ "log"
+ "os"
+ "os/exec"
+ "runtime"
+)
+
+var (
+ builderror chan string
+ restart chan bool
+ cmd *exec.Cmd
+)
+
+func init() {
+ builderror = make(chan string)
+ restart = make(chan bool)
+}
+
+func NewWatcher(paths []string) {
+ watcher, err := fsnotify.NewWatcher()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ go func() {
+ for {
+ select {
+ case e := <-watcher.Event:
+ fmt.Println(e)
+ go Autobuild()
+ case err := <-watcher.Error:
+ log.Fatal("error:", err)
+ }
+ }
+ }()
+ for _, path := range paths {
+ fmt.Println(path)
+ err = watcher.Watch(path)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+}
+
+func Autobuild() {
+ defer func() {
+ if err := recover(); err != nil {
+ str := ""
+ for i := 1; ; i += 1 {
+ _, file, line, ok := runtime.Caller(i)
+ if !ok {
+ break
+ }
+ str = str + fmt.Sprintf("%v,%v", file, line)
+ }
+ builderror <- str
+
+ }
+ }()
+ fmt.Println("Autobuild")
+ path, _ := os.Getwd()
+ os.Chdir(path)
+ bcmd := exec.Command("go", "build")
+ var out bytes.Buffer
+ var berr bytes.Buffer
+ bcmd.Stdout = &out
+ bcmd.Stderr = &berr
+ err := bcmd.Run()
+ if err != nil {
+ fmt.Println("run error", err)
+ }
+ if out.String() == "" {
+ Kill()
+ } else {
+ builderror <- berr.String()
+ }
+}
+
+func Kill() {
+ err := cmd.Process.Kill()
+ if err != nil {
+ panic(err)
+ }
+}
+
+func Start(appname string) {
+ fmt.Println("start", appname)
+ cmd = exec.Command(appname)
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ fmt.Println("stdout:", err)
+ }
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ fmt.Println("stdin:", err)
+ }
+ r := io.MultiReader(stdout, stderr)
+ err = cmd.Start()
+ if err != nil {
+ fmt.Println("cmd start:", err)
+ }
+ for {
+ buf := make([]byte, 1024)
+ count, err := r.Read(buf)
+ if err != nil || count == 0 {
+ fmt.Println("process exit")
+ restart <- true
+ return
+ } else {
+ fmt.Println("result:", string(buf))
+ }
+ }
+}