detached a921f70

feat: Added a `Config` struct and `GetConfig` function in config-provider.go

- Introduced a `Config` struct for better configuration handling.
- Created a `GetConfig` function to retrieve the configuration.

fix: Improved error handling and removed debug prints in htmx-installer.go

- Enhanced error handling in the Traefik installer.
- Removed unnecessary debug print statements.

refactor: Updated package dependencies and templates

- Updated package-lock.json and package.json for tailwindcss.
- Made template improvements in traefik-compose.goyml and traefik.goyml.

misc:

- Included the @catppuccin/tailwindcss plugin in the tailwind configuration.
commit
a921f708527c2b523a0569d2d7464fcdd84ff54d
author
bnema · · 2023-09-06 16:41 UTC
parent
a1ff1a2
signature
unsigned
12 files · +79 -17
M config/config-provider.go +10 -0
@@ -7,3 +7,13 @@ type Provider interface {
77 GetPublicFS() fs.FS
88 GetModelFS() fs.FS
99 }
10+
11+type Config struct {
12+ TemplateFS fs.FS
13+ PublicFS fs.FS
14+ ModelFS fs.FS
15+}
16+
17+func GetConfig() *Config {
18+ return &Config{}
19+}
@@ -7,3 +7,13 @@ type Provider interface {
7 GetPublicFS() fs.FS7 GetPublicFS() fs.FS
8 GetModelFS() fs.FS8 GetModelFS() fs.FS
9 }9 }
10+
11+type Config struct {
12+ TemplateFS fs.FS
13+ PublicFS fs.FS
14+ ModelFS fs.FS
15+}
16+
17+func GetConfig() *Config {
18+ return &Config{}
19+}
M internal/app/app.go +12 -0
@@ -111,3 +111,15 @@ func SetupLogging(config *Config) {
111111 }
112112 }
113113 }
114+
115+func GetBuildDir() string {
116+ env := os.Getenv(EnvVarName)
117+ buildDir := os.Getenv(BuildDirEnvVarName)
118+ if buildDir == "" {
119+ buildDir = DefaultBuildDir
120+ }
121+ if env == ProdEnvValue {
122+ return "."
123+ }
124+ return "./" + buildDir
125+}
@@ -111,3 +111,15 @@ func SetupLogging(config *Config) {
111 }111 }
112 }112 }
113 }113 }
114+
115+func GetBuildDir() string {
116+ env := os.Getenv(EnvVarName)
117+ buildDir := os.Getenv(BuildDirEnvVarName)
118+ if buildDir == "" {
119+ buildDir = DefaultBuildDir
120+ }
121+ if env == ProdEnvValue {
122+ return "."
123+ }
124+ return "./" + buildDir
125+}
M internal/http/handlers/htmx-installer.go +1 -5
@@ -1,8 +1,6 @@
11 package handlers
22
33 import (
4- "fmt"
5-
64 "github.com/labstack/echo/v4"
75 "gogs.bnema.dev/gordon-echo/pkg/scripts"
86 "gogs.bnema.dev/gordon-echo/pkg/utils"
@@ -10,8 +8,8 @@ import (
108
119 // TraefikInstallerHandler handles the installation of Traefik
1210 func TraefikInstallerHandler(c echo.Context) error {
13- // Retrieve the logger from the context
1411 logger := c.Get("logger").(*utils.Logger)
12+ // Retrieve the logger from the context
1513 // Reject POST requests if they are not allowed with the RejectPOSTPolicy function
1614 if err := RejectPOSTPolicy(c); err != nil {
1715 logger.Error().Err(err).Msg("POST request rejected")
@@ -30,8 +28,6 @@ func TraefikInstallerHandler(c echo.Context) error {
3028 return err
3129 }
3230
33- fmt.Println("POST request PAYLOAD=", topDomain, adminEmail)
34-
3531 // Call to create the YAML files
3632 err = scripts.CreateYAMLFiles(topDomain, adminEmail, logger)
3733 if err != nil {
@@ -1,8 +1,6 @@
1 package handlers1 package handlers
2 2
3 import (3 import (
4- "fmt"
5-
6 "github.com/labstack/echo/v4"4 "github.com/labstack/echo/v4"
7 "gogs.bnema.dev/gordon-echo/pkg/scripts"5 "gogs.bnema.dev/gordon-echo/pkg/scripts"
8 "gogs.bnema.dev/gordon-echo/pkg/utils"6 "gogs.bnema.dev/gordon-echo/pkg/utils"
@@ -10,8 +8,8 @@ import (
10 8
11 // TraefikInstallerHandler handles the installation of Traefik9 // TraefikInstallerHandler handles the installation of Traefik
12 func TraefikInstallerHandler(c echo.Context) error {10 func TraefikInstallerHandler(c echo.Context) error {
13- // Retrieve the logger from the context
14 logger := c.Get("logger").(*utils.Logger)11 logger := c.Get("logger").(*utils.Logger)
12+ // Retrieve the logger from the context
15 // Reject POST requests if they are not allowed with the RejectPOSTPolicy function13 // Reject POST requests if they are not allowed with the RejectPOSTPolicy function
16 if err := RejectPOSTPolicy(c); err != nil {14 if err := RejectPOSTPolicy(c); err != nil {
17 logger.Error().Err(err).Msg("POST request rejected")15 logger.Error().Err(err).Msg("POST request rejected")
@@ -30,8 +28,6 @@ func TraefikInstallerHandler(c echo.Context) error {
30 return err28 return err
31 }29 }
32 30
33- fmt.Println("POST request PAYLOAD=", topDomain, adminEmail)
34-
35 // Call to create the YAML files31 // Call to create the YAML files
36 err = scripts.CreateYAMLFiles(topDomain, adminEmail, logger)32 err = scripts.CreateYAMLFiles(topDomain, adminEmail, logger)
37 if err != nil {33 if err != nil {
M internal/http/routes/router.go +1 -0
@@ -9,6 +9,7 @@ import (
99 )
1010
1111 func ConfigureRouter(e *echo.Echo, app *app.App) *echo.Echo {
12+
1213 // SetLogger is a middleware that sets the logger in the context
1314 e.Use(middlewares.SetLogger(app.HttpLogger))
1415 // HTTPAccessLogger is a middleware that logs HTTP requests
@@ -9,6 +9,7 @@ import (
9 )9 )
10 10
11 func ConfigureRouter(e *echo.Echo, app *app.App) *echo.Echo {11 func ConfigureRouter(e *echo.Echo, app *app.App) *echo.Echo {
12+
12 // SetLogger is a middleware that sets the logger in the context13 // SetLogger is a middleware that sets the logger in the context
13 e.Use(middlewares.SetLogger(app.HttpLogger))14 e.Use(middlewares.SetLogger(app.HttpLogger))
14 // HTTPAccessLogger is a middleware that logs HTTP requests15 // HTTPAccessLogger is a middleware that logs HTTP requests
M internal/ui/templates/install.gohtml +4 -1
@@ -20,7 +20,10 @@
2020 <script src="/assets/js/custom.js"></script>
2121 </head>
2222
23- <body class="IBMPlexSans bg-zinc-200 md:p-8 flex flex-col items-center">
23+ <body
24+ class="IBMPlexSans bg-zinc-200 md:p-8 flex flex-col items-center"
25+ hx-boost="true"
26+ >
2427 <!-- Logo and Title -->
2528 <div
2629 id="logo-mascot"
@@ -20,7 +20,10 @@
20 <script src="/assets/js/custom.js"></script>20 <script src="/assets/js/custom.js"></script>
21 </head>21 </head>
22 22
23- <body class="IBMPlexSans bg-zinc-200 md:p-8 flex flex-col items-center">23+ <body
24+ class="IBMPlexSans bg-zinc-200 md:p-8 flex flex-col items-center"
25+ hx-boost="true"
26+ >
24 <!-- Logo and Title -->27 <!-- Logo and Title -->
25 <div28 <div
26 id="logo-mascot"29 id="logo-mascot"
M package-lock.json +10 -0 generated file: collapsed
M package.json +1 -0
@@ -1,5 +1,6 @@
11 {
22 "devDependencies": {
3+ "@catppuccin/tailwindcss": "^0.1.6",
34 "tailwindcss": "^3.3.3"
45 },
56 "scripts": {
@@ -1,5 +1,6 @@
1 {1 {
2 "devDependencies": {2 "devDependencies": {
3+ "@catppuccin/tailwindcss": "^0.1.6",
3 "tailwindcss": "^3.3.3"4 "tailwindcss": "^3.3.3"
4 },5 },
5 "scripts": {6 "scripts": {
M pkg/scripts/install-traefik.go +27 -7
@@ -1,15 +1,34 @@
11 package scripts
22
33 import (
4+ "errors"
5+ "fmt"
46 "os"
57
8+ root "gogs.bnema.dev/gordon-echo"
9+ "gogs.bnema.dev/gordon-echo/internal/app"
610 "gogs.bnema.dev/gordon-echo/pkg/templating"
711 "gogs.bnema.dev/gordon-echo/pkg/utils"
812 )
913
1014 func CreateYAMLFiles(topDomain, adminEmail string, logger *utils.Logger) error {
15+ path := app.GetBuildDir() + "/"
16+ modelFS := root.ModelFS
17+ if modelFS == nil {
18+ return errors.New("modelFS is nil")
19+ }
20+
21+ // Check if directory traefik exists, if not create it
22+ if _, err := os.Stat(path + "traefik"); os.IsNotExist(err) {
23+ err = os.Mkdir(path+"traefik", 0755)
24+ if err != nil {
25+ return err
26+ }
27+ }
28+
1129 // Setup the TXT renderer for traefik-compose.goyml
12- rendererCompose, err := templating.GetTXTRenderer("traefik-compose.goyml", nil, logger)
30+ rendererCompose, err := templating.GetTXTRenderer("traefik-compose.goyml", modelFS, logger)
31+ fmt.Println("rendererCompose=", rendererCompose)
1332 if err != nil {
1433 return err
1534 }
@@ -18,18 +37,18 @@ func CreateYAMLFiles(topDomain, adminEmail string, logger *utils.Logger) error {
1837 composeContent, err := rendererCompose.TXTRender(map[string]string{
1938 "topdomain": topDomain,
2039 })
40+ fmt.Println("composeContent=", composeContent)
2141 if err != nil {
2242 return err
2343 }
24-
25- // Save the rendered content to a file
26- err = os.WriteFile("traefik-compose.yml", []byte(composeContent), 0644)
44+ // Save the rendered content to a file at the env path
45+ err = os.WriteFile(path+"docker-compose.yml", []byte(composeContent), 0644)
2746 if err != nil {
2847 return err
2948 }
3049
3150 // Setup the TXT renderer for traefik.goyml
32- rendererTraefik, err := templating.GetTXTRenderer("traefik.goyml", nil, logger)
51+ rendererTraefik, err := templating.GetTXTRenderer("traefik.goyml", modelFS, logger)
3352 if err != nil {
3453 return err
3554 }
@@ -42,11 +61,12 @@ func CreateYAMLFiles(topDomain, adminEmail string, logger *utils.Logger) error {
4261 return err
4362 }
4463
45- // Save the rendered content to a file
46- err = os.WriteFile("traefik/traefik.yml", []byte(traefikContent), 0644)
64+ // Save the rendered content to a file at the env path
65+ err = os.WriteFile(path+"traefik/traefik.yml", []byte(traefikContent), 0644)
4766 if err != nil {
4867 return err
4968 }
5069
5170 return nil
71+
5272 }
@@ -1,15 +1,34 @@
1 package scripts1 package scripts
2 2
3 import (3 import (
4+ "errors"
5+ "fmt"
4 "os"6 "os"
5 7
8+ root "gogs.bnema.dev/gordon-echo"
9+ "gogs.bnema.dev/gordon-echo/internal/app"
6 "gogs.bnema.dev/gordon-echo/pkg/templating"10 "gogs.bnema.dev/gordon-echo/pkg/templating"
7 "gogs.bnema.dev/gordon-echo/pkg/utils"11 "gogs.bnema.dev/gordon-echo/pkg/utils"
8 )12 )
9 13
10 func CreateYAMLFiles(topDomain, adminEmail string, logger *utils.Logger) error {14 func CreateYAMLFiles(topDomain, adminEmail string, logger *utils.Logger) error {
15+ path := app.GetBuildDir() + "/"
16+ modelFS := root.ModelFS
17+ if modelFS == nil {
18+ return errors.New("modelFS is nil")
19+ }
20+
21+ // Check if directory traefik exists, if not create it
22+ if _, err := os.Stat(path + "traefik"); os.IsNotExist(err) {
23+ err = os.Mkdir(path+"traefik", 0755)
24+ if err != nil {
25+ return err
26+ }
27+ }
28+
11 // Setup the TXT renderer for traefik-compose.goyml29 // Setup the TXT renderer for traefik-compose.goyml
12- rendererCompose, err := templating.GetTXTRenderer("traefik-compose.goyml", nil, logger)30+ rendererCompose, err := templating.GetTXTRenderer("traefik-compose.goyml", modelFS, logger)
31+ fmt.Println("rendererCompose=", rendererCompose)
13 if err != nil {32 if err != nil {
14 return err33 return err
15 }34 }
@@ -18,18 +37,18 @@ func CreateYAMLFiles(topDomain, adminEmail string, logger *utils.Logger) error {
18 composeContent, err := rendererCompose.TXTRender(map[string]string{37 composeContent, err := rendererCompose.TXTRender(map[string]string{
19 "topdomain": topDomain,38 "topdomain": topDomain,
20 })39 })
40+ fmt.Println("composeContent=", composeContent)
21 if err != nil {41 if err != nil {
22 return err42 return err
23 }43 }
24-44+ // Save the rendered content to a file at the env path
25- // Save the rendered content to a file45+ err = os.WriteFile(path+"docker-compose.yml", []byte(composeContent), 0644)
26- err = os.WriteFile("traefik-compose.yml", []byte(composeContent), 0644)
27 if err != nil {46 if err != nil {
28 return err47 return err
29 }48 }
30 49
31 // Setup the TXT renderer for traefik.goyml50 // Setup the TXT renderer for traefik.goyml
32- rendererTraefik, err := templating.GetTXTRenderer("traefik.goyml", nil, logger)51+ rendererTraefik, err := templating.GetTXTRenderer("traefik.goyml", modelFS, logger)
33 if err != nil {52 if err != nil {
34 return err53 return err
35 }54 }
@@ -42,11 +61,12 @@ func CreateYAMLFiles(topDomain, adminEmail string, logger *utils.Logger) error {
42 return err61 return err
43 }62 }
44 63
45- // Save the rendered content to a file64+ // Save the rendered content to a file at the env path
46- err = os.WriteFile("traefik/traefik.yml", []byte(traefikContent), 0644)65+ err = os.WriteFile(path+"traefik/traefik.yml", []byte(traefikContent), 0644)
47 if err != nil {66 if err != nil {
48 return err67 return err
49 }68 }
50 69
51 return nil70 return nil
71+
52 }72 }
M pkg/templating/models/traefik-compose.goyml +1 -1
@@ -14,7 +14,7 @@ services:
1414 - /home/brice/traefik/data/acme.json:/acme.json
1515 labels:
1616 - "traefik.enable=true"
17- - "traefik.http.routers.api.rule=Host(`traefik.{{ topdomain }}`)"
17+ - "traefik.http.routers.api.rule=Host(`traefik.{{ .topdomain }}`)"
1818 - "traefik.http.routers.api.service=api@internal"
1919 - "traefik.http.routers.api.entrypoints=websecure"
2020 - "traefik.http.routers.api.tls.certresolver=myresolver"
@@ -14,7 +14,7 @@ services:
14 - /home/brice/traefik/data/acme.json:/acme.json14 - /home/brice/traefik/data/acme.json:/acme.json
15 labels:15 labels:
16 - "traefik.enable=true"16 - "traefik.enable=true"
17- - "traefik.http.routers.api.rule=Host(`traefik.{{ topdomain }}`)"17+ - "traefik.http.routers.api.rule=Host(`traefik.{{ .topdomain }}`)"
18 - "traefik.http.routers.api.service=api@internal"18 - "traefik.http.routers.api.service=api@internal"
19 - "traefik.http.routers.api.entrypoints=websecure"19 - "traefik.http.routers.api.entrypoints=websecure"
20 - "traefik.http.routers.api.tls.certresolver=myresolver"20 - "traefik.http.routers.api.tls.certresolver=myresolver"
M pkg/templating/models/traefik.goyml +1 -1
@@ -15,7 +15,7 @@ providers:
1515 certificatesResolvers:
1616 myresolver:
1717 acme:
18- email: {{ admin.email }}
18+ email: {{ .admin.email }}
1919 storage: acme.json
2020 httpChallenge:
2121 entryPoint: web
@@ -15,7 +15,7 @@ providers:
15 certificatesResolvers:15 certificatesResolvers:
16 myresolver:16 myresolver:
17 acme:17 acme:
18- email: {{ admin.email }}18+ email: {{ .admin.email }}
19 storage: acme.json19 storage: acme.json
20 httpChallenge:20 httpChallenge:
21 entryPoint: web21 entryPoint: web
M pkg/templating/txt-render.go +10 -1
@@ -3,6 +3,7 @@ package templating
33 import (
44 "bytes"
55 "errors"
6+ "fmt"
67 "io/fs"
78 "text/template"
89
@@ -24,7 +25,7 @@ func (r *TXTRenderer) TXTRender(data interface{}) (string, error) {
2425 }
2526
2627 if r.Models == nil {
27- err := errors.New("invalid or nil template")
28+ err := errors.New("invalid or nil model")
2829 r.Logger.Error().Err(r.ParseError).Msg("Parse error")
2930
3031 return "", err
@@ -42,6 +43,14 @@ func (r *TXTRenderer) TXTRender(data interface{}) (string, error) {
4243
4344 // GetRenderer function returns a new Renderer instance
4445 func GetTXTRenderer(filename string, fs fs.FS, logger *utils.Logger) (*TXTRenderer, error) {
46+ fmt.Println(filename)
47+ // Check if the file exists in the provided fs.FS using fs.Open
48+ file, err := fs.Open(filename)
49+ if err != nil {
50+ logger.Error().Err(err).Msg("Template or model '%s' not found" + filename)
51+ return nil, err
52+ }
53+ file.Close() // Close the file after checking
4554 mdls, err := template.New(filename).ParseFS(fs, filename)
4655 if err != nil {
4756 logger.Error().Err(err).Msg("Failed to parse template")
@@ -3,6 +3,7 @@ package templating
3 import (3 import (
4 "bytes"4 "bytes"
5 "errors"5 "errors"
6+ "fmt"
6 "io/fs"7 "io/fs"
7 "text/template"8 "text/template"
8 9
@@ -24,7 +25,7 @@ func (r *TXTRenderer) TXTRender(data interface{}) (string, error) {
24 }25 }
25 26
26 if r.Models == nil {27 if r.Models == nil {
27- err := errors.New("invalid or nil template")28+ err := errors.New("invalid or nil model")
28 r.Logger.Error().Err(r.ParseError).Msg("Parse error")29 r.Logger.Error().Err(r.ParseError).Msg("Parse error")
29 30
30 return "", err31 return "", err
@@ -42,6 +43,14 @@ func (r *TXTRenderer) TXTRender(data interface{}) (string, error) {
42 43
43 // GetRenderer function returns a new Renderer instance44 // GetRenderer function returns a new Renderer instance
44 func GetTXTRenderer(filename string, fs fs.FS, logger *utils.Logger) (*TXTRenderer, error) {45 func GetTXTRenderer(filename string, fs fs.FS, logger *utils.Logger) (*TXTRenderer, error) {
46+ fmt.Println(filename)
47+ // Check if the file exists in the provided fs.FS using fs.Open
48+ file, err := fs.Open(filename)
49+ if err != nil {
50+ logger.Error().Err(err).Msg("Template or model '%s' not found" + filename)
51+ return nil, err
52+ }
53+ file.Close() // Close the file after checking
45 mdls, err := template.New(filename).ParseFS(fs, filename)54 mdls, err := template.New(filename).ParseFS(fs, filename)
46 if err != nil {55 if err != nil {
47 logger.Error().Err(err).Msg("Failed to parse template")56 logger.Error().Err(err).Msg("Failed to parse template")
M tailwind.config.js +1 -1
@@ -14,5 +14,5 @@ module.exports = {
1414 },
1515 },
1616 },
17- plugins: [],
17+ plugins: [require("@catppuccin/tailwindcss")],
1818 }⏎̸
@@ -14,5 +14,5 @@ module.exports = {
14 },14 },
15 },15 },
16 },16 },
17- plugins: [],17+ plugins: [require("@catppuccin/tailwindcss")],
18 }⏎̸18 }⏎̸

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close