Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -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=
35 changes: 35 additions & 0 deletions slick/cmd.go
Original file line number Diff line number Diff line change
@@ -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()
}
235 changes: 146 additions & 89 deletions slick/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -130,6 +186,7 @@ func writeMainContents(mod string) []byte {
package main

import (
"log"
"github.com/anthdm/slick"
"%s/handler"
)
Expand Down