diff --git a/go.mod b/go.mod index fae664a..17aab5d 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,13 @@ module github.com/anthdm/slick -go 1.21.0 +go 1.21 require ( github.com/a-h/templ v0.2.476 github.com/julienschmidt/httprouter v1.3.0 + github.com/joho/godotenv v1.5.1 + github.com/spf13/cobra v1.8.0 + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect ) -require github.com/joho/godotenv v1.5.1 diff --git a/go.sum b/go.sum index 1a163ab..642ebf6 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,18 @@ github.com/a-h/templ v0.2.476 h1:+H4hP4CwK4kfJwXsE6kHeFWMGtcVOVoOm/I64uzARBk= github.com/a-h/templ v0.2.476/go.mod h1:zQ95mSyadNTGHv6k5Fm+wQU8zkBMMbHCHg7eAvUZKNM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/slick/cmd.go b/slick/cmd.go new file mode 100644 index 0000000..194e03e --- /dev/null +++ b/slick/cmd.go @@ -0,0 +1,35 @@ +package main + +import ( + "github.com/spf13/cobra" +) + +type commandFunc func() *cobra.Command + +type cli struct { + cmds []commandFunc +} + +func NewCommand() *cli { + return &cli{ + cmds: make([]commandFunc, 0), + } +} + +func (c *cli) Register(cmds ...commandFunc) { + c.cmds = append(c.cmds, cmds...) +} + +func (c *cli) Execute() { + rootCmd := &cobra.Command{ + Use: "slick", + Short: "Slick CLI", + Long: "Slick web framework", + } + + for _, command := range c.cmds { + rootCmd.AddCommand(command()) + } + + rootCmd.Execute() +} diff --git a/slick/main.go b/slick/main.go index 2c8ff83..d4b2b38 100644 --- a/slick/main.go +++ b/slick/main.go @@ -6,111 +6,167 @@ import ( "os/exec" "strings" "time" + + "github.com/spf13/cobra" ) -func usage() { - fmt.Println("help....") - os.Exit(0) +func main() { + cmd := NewCommand() + cmd.Register( + runProject, + installProject, + generateProject, + generateModel, + generateView, + generateHandler, + ) + + cmd.Execute() } -func main() { - args := os.Args - if len(args) < 2 { - usage() - } - cmd := os.Args[1] - - switch cmd { - case "run": - if _, err := os.Stat("cmd/main.go"); err != nil { - fmt.Println("not in slick app root: cmd/main.go not found") - os.Exit(1) - } - if err := exec.Command("templ", "generate").Run(); err != nil { - fmt.Println(err) - os.Exit(1) - } - exec.Command("go", "run", "cmd/main.go").Run() - case "install": - if err := installProject(); err != nil { - fmt.Println(err) - } - case "new": - if len(os.Args) != 3 { - usage() - } - name := os.Args[2] - if err := generateProject(name); err != nil { - fmt.Println(err) - } +func runProject() *cobra.Command { + return &cobra.Command{ + Use: "run", + Example: "slick run", + Short: "Run slick development server", + Run: func(cmd *cobra.Command, args []string) { + if _, err := os.Stat("cmd/main.go"); err != nil { + fmt.Println("not in slick app root: cmd/main.go not found") + return + } + if err := exec.Command("templ", "generate").Run(); err != nil { + fmt.Println(err) + return + } + + if err := exec.Command("go", "run", "cmd/main.go").Run(); err != nil { + fmt.Println(err) + } + }, } } -func generateProject(name string) error { - fmt.Println("creating new slick project:", name) - if err := os.Mkdir(name, os.ModePerm); err != nil { - return err +func installProject() *cobra.Command { + return &cobra.Command{ + Use: "install", + Aliases: []string{"i"}, + Example: "slick install", + Short: "Install project's dependency", + Run: func(cmd *cobra.Command, args []string) { + start := time.Now() + fmt.Println("installing project...") + if err := exec.Command("go", "get", "github.com/anthdm/slick@latest").Run(); err != nil { + fmt.Println(err) + return + } + + if err := exec.Command("go", "get", "github.com/a-h/templ").Run(); err != nil { + fmt.Println(err) + return + } + if err := exec.Command("templ", "generate").Run(); err != nil { + fmt.Println(err) + return + } + + fmt.Printf("done installing project in %v\n", time.Since(start)) + }, } +} - folders := []string{"model", "handler", "view", "cmd", "public"} - - for _, folder := range folders { - if err := os.Mkdir(name+"/"+folder, os.ModePerm); err != nil { - return err - } +func generateProject() *cobra.Command { + return &cobra.Command{ + Use: "new", + Example: "slick new hello-world", + Short: "Create new slick project", + Run: func(cmd *cobra.Command, args []string) { + name := args[0] + + fmt.Println("creating new slick project:", name) + if err := os.Mkdir(name, os.ModePerm); err != nil { + fmt.Println(err) + return + } + + folders := []string{"model", "handler", "view", "cmd", "public"} + + for _, folder := range folders { + if err := os.Mkdir(name+"/"+folder, os.ModePerm); err != nil { + fmt.Println(err) + } + } + + // TODO: imrpove this error handling + if err := os.WriteFile(name+"/go.mod", writeGoModContents(name), os.ModePerm); err != nil { + fmt.Println(err) + } + if err := os.WriteFile(name+"/.air.toml", writeAirTomlContents(), os.ModePerm); err != nil { + fmt.Println(err) + } + if err := os.WriteFile(name+"/.env", writeEnvFileContents(), os.ModePerm); err != nil { + fmt.Println(err) + } + if err := os.WriteFile(name+"/.gitignore", writeGitignore(), os.ModePerm); err != nil { + fmt.Println(err) + } + if err := os.WriteFile(name+"/public/app.css", []byte(""), os.ModePerm); err != nil { + fmt.Println(err) + } + if err := os.WriteFile(name+"/cmd/main.go", writeMainContents(name), os.ModePerm); err != nil { + fmt.Println(err) + } + if err := os.WriteFile(name+"/handler/hello.go", writeHandlerContent(name), os.ModePerm); err != nil { + fmt.Println(err) + } + if err := os.Mkdir(name+"/view/hello", os.ModePerm); err != nil { + fmt.Println(err) + } + if err := os.Mkdir(name+"/view/layout", os.ModePerm); err != nil { + fmt.Println(err) + } + if err := os.WriteFile(name+"/view/layout/base.templ", writeBaseLayoutContent(), os.ModePerm); err != nil { + fmt.Println(err) + } + if err := os.WriteFile(name+"/view/hello/hello.templ", writeViewContent(name), os.ModePerm); err != nil { + fmt.Println(err) + } + }, } +} - if err := os.WriteFile(name+"/go.mod", writeGoModContents(name), os.ModePerm); err != nil { - return err - } - if err := os.WriteFile(name+"/.air.toml", writeAirTomlContents(), os.ModePerm); err != nil { - return err - } - if err := os.WriteFile(name+"/.env", writeEnvFileContents(), os.ModePerm); err != nil { - return err - } - if err := os.WriteFile(name+"/.gitignore", writeGitignore(), os.ModePerm); err != nil { - return err - } - if err := os.WriteFile(name+"/public/app.css", []byte(""), os.ModePerm); err != nil { - return err - } - if err := os.WriteFile(name+"/cmd/main.go", writeMainContents(name), os.ModePerm); err != nil { - return err +func generateModel() *cobra.Command { + return &cobra.Command{ + Use: "model", + Example: "slick model user", + Short: "Generate new model", + Run: func(cmd *cobra.Command, args []string) { + // TODO: + }, } - if err := os.WriteFile(name+"/handler/hello.go", writeHandlerContent(name), os.ModePerm); err != nil { - return err - } - if err := os.Mkdir(name+"/view/hello", os.ModePerm); err != nil { - return err - } - if err := os.Mkdir(name+"/view/layout", os.ModePerm); err != nil { - return err - } - if err := os.WriteFile(name+"/view/layout/base.templ", writeBaseLayoutContent(), os.ModePerm); err != nil { - return err - } - if err := os.WriteFile(name+"/view/hello/hello.templ", writeViewContent(name), os.ModePerm); err != nil { - return err - } - - return nil } -func installProject() error { - start := time.Now() - fmt.Println("installing project...") - if err := exec.Command("go", "get", "github.com/anthdm/slick@latest").Run(); err != nil { - return err - } - if err := exec.Command("go", "get", "github.com/a-h/templ").Run(); err != nil { - return err +func generateView() *cobra.Command { + return &cobra.Command{ + Use: "view", + Example: "slick view user", + Short: "Generate new view", + Run: func(cmd *cobra.Command, args []string) { + // TODO: + + }, } - if err := exec.Command("templ", "generate").Run(); err != nil { - return err +} + +func generateHandler() *cobra.Command { + return &cobra.Command{ + Use: "handler", + Example: "slick handler home", + Short: "Generate new handler", + Run: func(cmd *cobra.Command, args []string) { + // TODO: + + }, } - fmt.Printf("done installing project in %v\n", time.Since(start)) - return nil } func writeEnvFileContents() []byte { @@ -130,6 +186,7 @@ func writeMainContents(mod string) []byte { package main import ( + "log" "github.com/anthdm/slick" "%s/handler" )