From 2bd76a9b96e9033dd1402ff3706ddec44c11b2da Mon Sep 17 00:00:00 2001 From: cubixle Date: Fri, 22 Jul 2022 13:15:26 +0100 Subject: [PATCH] start of creating a new project cmd --- README.md | 8 ++ go.mod | 3 + main.go | 106 ++++++++++++++++ maker/project.go | 189 +++++++++++++++++++++++++++++ maker/resource.go | 5 + templates/config.yml | 2 + templates/internal/http/default.go | 25 ++++ templates/internal/http/http.go | 18 +++ templates/main.go.tmpl | 43 +++++++ templates/views/error.html | 0 templates/views/index.html | 11 ++ 11 files changed, 410 insertions(+) create mode 100644 README.md create mode 100644 go.mod create mode 100644 main.go create mode 100644 maker/project.go create mode 100644 maker/resource.go create mode 100644 templates/config.yml create mode 100644 templates/internal/http/default.go create mode 100644 templates/internal/http/http.go create mode 100644 templates/main.go.tmpl create mode 100644 templates/views/error.html create mode 100644 templates/views/index.html diff --git a/README.md b/README.md new file mode 100644 index 0000000..630aec3 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Tuukoti CLI + +## Commands + +- `tuukoti new sitename` - creates a new project directory with "sitename". +- `tuukoti serve` - serves your app locally. +- `tuukoti build` - builds the binary and any resources. +- `tuukoti update` diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9fdcbfb --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/tuukoti/cli + +go 1.18 diff --git a/main.go b/main.go new file mode 100644 index 0000000..ea0ad45 --- /dev/null +++ b/main.go @@ -0,0 +1,106 @@ +package main + +import ( + "embed" + "fmt" + "os" + + "github.com/tuukoti/cli/maker" +) + +const colorRed = "\033[0;31m" +const colorGreen = "\033[0;32m" +const colorBlue = "\033[0;34m" +const colorYellow = "\033[93m" +const colorNone = "\033[0m" +const newLine = "\n" + +var Version = "develop" + +//go:embed templates +var fs embed.FS + +func main() { + if err := runCLI(); err != nil { + fmt.Printf("%s%s%s", colorRed, err, newLine) + } + + fmt.Println("") +} + +func runCLI() error { + + fmt.Println("------------------") + fmt.Printf("Tuukoti CLI - %s%s", Version, newLine) + fmt.Println("------------------") + fmt.Println("") + + args := os.Args + if len(args) == 1 { + err := fmt.Errorf("missing command, try `tuukoti list` to see what you can run.") + + fmt.Println(err) + + return nil + } + + switch os.Args[1] { + case "list": + printCmd("new sitename", "create a new project within the directory of sitename") + printCmd("serve", "serves your app locally") + printCmd("build", "build the binary and any resources configured") + printCmd("list", "list displays a list of all commands") + printCmd("version", "displays the cli tools current version") + fmt.Println("") + printHeader("make") + printCmd("make resource", "creates a new route file and a ") + case "version": + fmt.Println("") + version() + case "new": + err := maker.Project(fs, os.Args[2]) + if err != nil { + return err + } + + fmt.Printf("%sproject %s has been created%s", colorGreen, os.Args[2], newLine) + case "serve": + + case "build": + + case "make": + if len(os.Args) == 2 { + fmt.Printf("missing what we should make %s", newLine) + return nil + } + + switch os.Args[2] { + case "resource": + resourceName := os.Args[3] + + err := maker.Resource(resourceName) + if err != nil { + return err + } + } + + default: + err := fmt.Errorf("missing command, try `tuukoti list` to see what you can run.") + + fmt.Println(err) + } + + return nil +} + +func version() { + fmt.Printf("Version: %s%s", Version, newLine) +} + +func printCmd(commandName, desc string) { + fmt.Printf(" %s%-12s %s- %s.%s", colorGreen, commandName, colorNone, desc, newLine) +} + +func printHeader(h string) { + fmt.Printf("%s%s%s", colorYellow, h, newLine) +} diff --git a/maker/project.go b/maker/project.go new file mode 100644 index 0000000..a029a3a --- /dev/null +++ b/maker/project.go @@ -0,0 +1,189 @@ +package maker + +import ( + "fmt" + "io" + "io/fs" + "os" + "path/filepath" +) + +func Project(fs fs.FS, name string) error { + _, err := os.Stat(name) + if err != nil { + if !os.IsNotExist(err) { + return err + } + } + + if err == nil { + return fmt.Errorf("project folder already exists") + } + + absPath, err := filepath.Abs(name) + if err != nil { + return err + } + + err = os.Mkdir(absPath, 0777) + if err != nil { + return fmt.Errorf("failed to create the project folder, %w", err) + } + + err = makeProject(fs, absPath, name) + if err != nil { + rerr := os.RemoveAll(absPath) + if rerr != nil { + return rerr + } + + return err + } + + return nil +} + +func makeProject(fs fs.FS, absPath, name string) error { + // check if folder already exists + err := mainfile(fs, absPath, name) + if err != nil { + return err + } + + err = defaultHTTPRoutes(fs, absPath) + if err != nil { + return err + } + + err = defaultHomepage(fs, absPath) + if err != nil { + return err + } + + err = defaultConfig(fs, absPath) + if err != nil { + return err + } + + return nil + +} + +func mainfile(fs fs.FS, path, projectName string) error { + path = filepath.Join(path, "cmd", projectName) + + err := os.MkdirAll(path, 0777) + if err != nil { + return err + } + + f, err := os.Create(filepath.Join(path, "main.go")) + if err != nil { + return err + } + + tmpl, err := fs.Open("templates/main.go") + if err != nil { + return err + } + + _, err = io.Copy(f, tmpl) + if err != nil { + return err + } + + err = f.Close() + if err != nil { + return err + } + + return nil +} + +// defaultHTTPRoutes will create a ./http dir with a http.go file. +// In this file we will register 1 route and 2 route handlers. +// The first handle is the home "/" handler. +// The second handler is a 404 handler. +func defaultHTTPRoutes(fs fs.FS, path string) error { + path = filepath.Join(path, "internal", "http") + + err := os.MkdirAll(path, 0777) + if err != nil { + return err + } + + f, err := os.Create(filepath.Join(path, "http.go")) + if err != nil { + return err + } + + tmpl, err := fs.Open("templates/http/http.go") + if err != nil { + return err + } + + _, err = io.Copy(f, tmpl) + if err != nil { + return err + } + + err = f.Close() + if err != nil { + return err + } + + return nil +} + +func defaultHomepage(fs fs.FS, path string) error { + err := os.Mkdir(filepath.Join(path, "template"), 0777) + if err != nil { + return err + } + + f, err := os.Create(filepath.Join(path, "templates", "index.html")) + if err != nil { + return err + } + + tmpl, err := fs.Open("templates/index.html") + if err != nil { + return err + } + + _, err = io.Copy(f, tmpl) + if err != nil { + return err + } + + err = f.Close() + if err != nil { + return err + } + + return nil +} + +func defaultConfig(fs fs.FS, path string) error { + f, err := os.Create(filepath.Join(path, "config.yml")) + if err != nil { + return err + } + + tmpl, err := fs.Open("templates/config.yml") + if err != nil { + return err + } + + _, err = io.Copy(f, tmpl) + if err != nil { + return err + } + + err = f.Close() + if err != nil { + return err + } + + return nil +} diff --git a/maker/resource.go b/maker/resource.go new file mode 100644 index 0000000..d3ebaa3 --- /dev/null +++ b/maker/resource.go @@ -0,0 +1,5 @@ +package maker + +func Resource(name string) error { + return nil +} diff --git a/templates/config.yml b/templates/config.yml new file mode 100644 index 0000000..feda489 --- /dev/null +++ b/templates/config.yml @@ -0,0 +1,2 @@ +host: localhost:8080 +debug: false diff --git a/templates/internal/http/default.go b/templates/internal/http/default.go new file mode 100644 index 0000000..27a1488 --- /dev/null +++ b/templates/internal/http/default.go @@ -0,0 +1,25 @@ +package http + +import ( + "net/http" + + "github.com/labstack/echo/v4" +) + +func (h *HTTP) DefaultHandler(c echo.Context) error { + return c.Render(http.StatusOK, "index.html", nil) +} + +func (h *HTTP) DefaultErrorHandler(err error, c echo.Context) { + code := http.StatusInternalServerError + if he, ok := err.(*echo.HTTPError); ok { + code = he.Code + } + + h.log.Error(err) + + err = c.Render(code, "error.html", nil) + if err != nil { + h.log.Error(err) + } +} diff --git a/templates/internal/http/http.go b/templates/internal/http/http.go new file mode 100644 index 0000000..1469e5d --- /dev/null +++ b/templates/internal/http/http.go @@ -0,0 +1,18 @@ +package http + +import ( + "github.com/labstack/echo/v4" + "github.com/sirupsen/logrus" +) + +type HTTP struct { + log *logrus.Logger +} + +func RegisterRoutes(e *echo.Echo, log *logrus.Logger) { + h := HTTP{log: log} + + e.HTTPErrorHandler = h.DefaultErrorHandler + + e.GET("/", h.DefaultHandler) +} diff --git a/templates/main.go.tmpl b/templates/main.go.tmpl new file mode 100644 index 0000000..b67eec6 --- /dev/null +++ b/templates/main.go.tmpl @@ -0,0 +1,43 @@ +package main + +import ( + "log" + "os" + + "github.com/cubixle/testing/internal/http" + "github.com/labstack/echo/v4" + "github.com/sirupsen/logrus" + "github.com/tuukoti/framework/config" +) + +func main() { + if err := run(); err != nil { + log.Fatal(err) + } +} + +func run() error { + cfgPath := getEnv("TUUKOTI_CONFIG", "./config.yml") + + cfg, err := config.Load(cfgPath) + if err != nil { + return err + } + + log := logrus.New() + + e := echo.New() + + http.RegisterRoutes(e, log) + + return e.Start(cfg.Host) +} + +func getEnv(name, defaultValue string) string { + v := os.Getenv(name) + if v == "" { + return defaultValue + } + + return v +} diff --git a/templates/views/error.html b/templates/views/error.html new file mode 100644 index 0000000..e69de29 diff --git a/templates/views/index.html b/templates/views/index.html new file mode 100644 index 0000000..bcacc65 --- /dev/null +++ b/templates/views/index.html @@ -0,0 +1,11 @@ + + + + Tuukoti + + + +

Tuukoti

+ + +