detached c9f4eea

SQL + sqlite in memory drivers ok | Index.gohtml rendered at AdminPath

commit
c9f4eea3ab75816c9b1fb72d7dd043789e16b142
author
bnema · · 2023-09-14 15:05 UTC
parent
accf0b9
signature
unsigned
7 files · +283 -21
M go.mod +21 -0
@@ -4,25 +4,46 @@ go 1.21.1
44
55 require (
66 github.com/PuerkitoBio/goquery v1.8.1
7+ github.com/docker/docker v24.0.6+incompatible
78 github.com/labstack/echo-contrib v0.15.0
89 github.com/labstack/echo/v4 v4.11.1
10+ github.com/mattn/go-sqlite3 v1.14.17
911 gopkg.in/yaml.v3 v3.0.1
1012 )
1113
1214 require (
15+ github.com/Microsoft/go-winio v0.6.1 // indirect
1316 github.com/andybalholm/cascadia v1.3.1 // indirect
17+ github.com/containerd/containerd v1.7.6 // indirect
18+ github.com/docker/distribution v2.8.2+incompatible // indirect
19+ github.com/docker/go-connections v0.4.0 // indirect
20+ github.com/docker/go-units v0.5.0 // indirect
21+ github.com/gogo/protobuf v1.3.2 // indirect
1422 github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
1523 github.com/gorilla/context v1.1.1 // indirect
1624 github.com/gorilla/securecookie v1.1.1 // indirect
1725 github.com/gorilla/sessions v1.2.1 // indirect
26+ github.com/klauspost/compress v1.16.7 // indirect
1827 github.com/labstack/gommon v0.4.0 // indirect
1928 github.com/mattn/go-colorable v0.1.13 // indirect
2029 github.com/mattn/go-isatty v0.0.19 // indirect
30+ github.com/moby/patternmatcher v0.6.0 // indirect
31+ github.com/moby/sys/sequential v0.5.0 // indirect
32+ github.com/moby/term v0.5.0 // indirect
33+ github.com/morikuni/aec v1.0.0 // indirect
34+ github.com/opencontainers/go-digest v1.0.0 // indirect
35+ github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect
36+ github.com/opencontainers/runc v1.1.9 // indirect
37+ github.com/pkg/errors v0.9.1 // indirect
38+ github.com/sirupsen/logrus v1.9.3 // indirect
2139 github.com/valyala/bytebufferpool v1.0.0 // indirect
2240 github.com/valyala/fasttemplate v1.2.2 // indirect
2341 golang.org/x/crypto v0.11.0 // indirect
42+ golang.org/x/mod v0.9.0 // indirect
2443 golang.org/x/net v0.12.0 // indirect
2544 golang.org/x/sys v0.10.0 // indirect
2645 golang.org/x/text v0.11.0 // indirect
2746 golang.org/x/time v0.3.0 // indirect
47+ golang.org/x/tools v0.7.0 // indirect
48+ gotest.tools/v3 v3.5.0 // indirect
2849 )
@@ -4,25 +4,46 @@ go 1.21.1
4 4
5 require (5 require (
6 github.com/PuerkitoBio/goquery v1.8.16 github.com/PuerkitoBio/goquery v1.8.1
7+ github.com/docker/docker v24.0.6+incompatible
7 github.com/labstack/echo-contrib v0.15.08 github.com/labstack/echo-contrib v0.15.0
8 github.com/labstack/echo/v4 v4.11.19 github.com/labstack/echo/v4 v4.11.1
10+ github.com/mattn/go-sqlite3 v1.14.17
9 gopkg.in/yaml.v3 v3.0.111 gopkg.in/yaml.v3 v3.0.1
10 )12 )
11 13
12 require (14 require (
15+ github.com/Microsoft/go-winio v0.6.1 // indirect
13 github.com/andybalholm/cascadia v1.3.1 // indirect16 github.com/andybalholm/cascadia v1.3.1 // indirect
17+ github.com/containerd/containerd v1.7.6 // indirect
18+ github.com/docker/distribution v2.8.2+incompatible // indirect
19+ github.com/docker/go-connections v0.4.0 // indirect
20+ github.com/docker/go-units v0.5.0 // indirect
21+ github.com/gogo/protobuf v1.3.2 // indirect
14 github.com/golang-jwt/jwt v3.2.2+incompatible // indirect22 github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
15 github.com/gorilla/context v1.1.1 // indirect23 github.com/gorilla/context v1.1.1 // indirect
16 github.com/gorilla/securecookie v1.1.1 // indirect24 github.com/gorilla/securecookie v1.1.1 // indirect
17 github.com/gorilla/sessions v1.2.1 // indirect25 github.com/gorilla/sessions v1.2.1 // indirect
26+ github.com/klauspost/compress v1.16.7 // indirect
18 github.com/labstack/gommon v0.4.0 // indirect27 github.com/labstack/gommon v0.4.0 // indirect
19 github.com/mattn/go-colorable v0.1.13 // indirect28 github.com/mattn/go-colorable v0.1.13 // indirect
20 github.com/mattn/go-isatty v0.0.19 // indirect29 github.com/mattn/go-isatty v0.0.19 // indirect
30+ github.com/moby/patternmatcher v0.6.0 // indirect
31+ github.com/moby/sys/sequential v0.5.0 // indirect
32+ github.com/moby/term v0.5.0 // indirect
33+ github.com/morikuni/aec v1.0.0 // indirect
34+ github.com/opencontainers/go-digest v1.0.0 // indirect
35+ github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect
36+ github.com/opencontainers/runc v1.1.9 // indirect
37+ github.com/pkg/errors v0.9.1 // indirect
38+ github.com/sirupsen/logrus v1.9.3 // indirect
21 github.com/valyala/bytebufferpool v1.0.0 // indirect39 github.com/valyala/bytebufferpool v1.0.0 // indirect
22 github.com/valyala/fasttemplate v1.2.2 // indirect40 github.com/valyala/fasttemplate v1.2.2 // indirect
23 golang.org/x/crypto v0.11.0 // indirect41 golang.org/x/crypto v0.11.0 // indirect
42+ golang.org/x/mod v0.9.0 // indirect
24 golang.org/x/net v0.12.0 // indirect43 golang.org/x/net v0.12.0 // indirect
25 golang.org/x/sys v0.10.0 // indirect44 golang.org/x/sys v0.10.0 // indirect
26 golang.org/x/text v0.11.0 // indirect45 golang.org/x/text v0.11.0 // indirect
27 golang.org/x/time v0.3.0 // indirect46 golang.org/x/time v0.3.0 // indirect
47+ golang.org/x/tools v0.7.0 // indirect
48+ gotest.tools/v3 v3.5.0 // indirect
28 )49 )
M go.sum +75 -2 generated file: collapsed
M internal/app/app.go +29 -4
@@ -2,6 +2,7 @@ package app
22
33 import (
44 "io/fs"
5+ "path/filepath"
56
67 "github.com/bnema/gordon/internal/gotemplate"
78 "github.com/bnema/gordon/internal/webui"
@@ -10,11 +11,17 @@ import (
1011 const (
1112 BuildVersion = "0.0.2"
1213 BuildDir = "tmp"
14+ DBDir = "tmp/data"
15+ DBFilename = "sqlite.db"
1316 // Those configs should be read from a config file
14- HttpPort = 1323
15- TopDomain = "example.com"
16- SubDomain = "gordon"
17- AdminPath = "/admin"
17+ HttpPort = 1323
18+ TopDomain = "example.com"
19+ SubDomain = "gordon"
20+ AdminPath = "/admin"
21+ DockerSock = "/var/run/docker.sock"
22+ // If enabled replace all docker commands by podman
23+ PodmanEnable = false
24+ PodmanSock = "/run/user/1000/podman/podman.sock"
1825 )
1926
2027 type App struct {
@@ -22,9 +29,14 @@ type App struct {
2229 PublicFS fs.FS
2330 BuildVersion string
2431 BuildDir string
32+ DBDir string
33+ DBFilename string
2534 TopDomain string
2635 SubDomain string
2736 AdminPath string
37+ DockerSock string
38+ PodmanEnable bool
39+ PodmanSock string
2840 HttpPort int16
2941 }
3042
@@ -34,9 +46,22 @@ func NewApp() *App {
3446 PublicFS: webui.PublicFS,
3547 BuildVersion: BuildVersion,
3648 BuildDir: BuildDir,
49+ DBDir: DBDir,
50+ DBFilename: DBFilename,
3751 TopDomain: TopDomain,
3852 SubDomain: SubDomain,
3953 AdminPath: AdminPath,
4054 HttpPort: HttpPort,
4155 }
4256 }
57+
58+func NewDockerClient() *App {
59+ return &App{
60+ DockerSock: DockerSock,
61+ PodmanEnable: PodmanEnable,
62+ PodmanSock: PodmanSock,
63+ }
64+}
65+func (a *App) GetDBFilePath() string {
66+ return filepath.Join(a.DBDir, a.DBFilename)
67+}
@@ -2,6 +2,7 @@ package app
2 2
3 import (3 import (
4 "io/fs"4 "io/fs"
5+ "path/filepath"
5 6
6 "github.com/bnema/gordon/internal/gotemplate"7 "github.com/bnema/gordon/internal/gotemplate"
7 "github.com/bnema/gordon/internal/webui"8 "github.com/bnema/gordon/internal/webui"
@@ -10,11 +11,17 @@ import (
10 const (11 const (
11 BuildVersion = "0.0.2"12 BuildVersion = "0.0.2"
12 BuildDir = "tmp"13 BuildDir = "tmp"
14+ DBDir = "tmp/data"
15+ DBFilename = "sqlite.db"
13 // Those configs should be read from a config file16 // Those configs should be read from a config file
14- HttpPort = 132317+ HttpPort = 1323
15- TopDomain = "example.com"18+ TopDomain = "example.com"
16- SubDomain = "gordon"19+ SubDomain = "gordon"
17- AdminPath = "/admin"20+ AdminPath = "/admin"
21+ DockerSock = "/var/run/docker.sock"
22+ // If enabled replace all docker commands by podman
23+ PodmanEnable = false
24+ PodmanSock = "/run/user/1000/podman/podman.sock"
18 )25 )
19 26
20 type App struct {27 type App struct {
@@ -22,9 +29,14 @@ type App struct {
22 PublicFS fs.FS29 PublicFS fs.FS
23 BuildVersion string30 BuildVersion string
24 BuildDir string31 BuildDir string
32+ DBDir string
33+ DBFilename string
25 TopDomain string34 TopDomain string
26 SubDomain string35 SubDomain string
27 AdminPath string36 AdminPath string
37+ DockerSock string
38+ PodmanEnable bool
39+ PodmanSock string
28 HttpPort int1640 HttpPort int16
29 }41 }
30 42
@@ -34,9 +46,22 @@ func NewApp() *App {
34 PublicFS: webui.PublicFS,46 PublicFS: webui.PublicFS,
35 BuildVersion: BuildVersion,47 BuildVersion: BuildVersion,
36 BuildDir: BuildDir,48 BuildDir: BuildDir,
49+ DBDir: DBDir,
50+ DBFilename: DBFilename,
37 TopDomain: TopDomain,51 TopDomain: TopDomain,
38 SubDomain: SubDomain,52 SubDomain: SubDomain,
39 AdminPath: AdminPath,53 AdminPath: AdminPath,
40 HttpPort: HttpPort,54 HttpPort: HttpPort,
41 }55 }
42 }56 }
57+
58+func NewDockerClient() *App {
59+ return &App{
60+ DockerSock: DockerSock,
61+ PodmanEnable: PodmanEnable,
62+ PodmanSock: PodmanSock,
63+ }
64+}
65+func (a *App) GetDBFilePath() string {
66+ return filepath.Join(a.DBDir, a.DBFilename)
67+}
A internal/app/sqlite.go +108 -0
@@ -0,0 +1,108 @@
1+package app
2+
3+import (
4+ "context"
5+ "database/sql"
6+ "fmt"
7+ "os"
8+
9+ sqlite3 "github.com/mattn/go-sqlite3"
10+)
11+
12+// Initialize in-memory SQLite database and returns its connection
13+func InitDB() (db *sql.DB, err error) {
14+ db, err = sql.Open("sqlite3", "file::memory?cache=shared")
15+ if err != nil {
16+ return nil, fmt.Errorf("failed to open in-memory database: %v", err)
17+ }
18+ return
19+}
20+
21+// CloseDB closes the database connection and backs up the in-memory database to disk
22+func CloseDB(db *sql.DB, a *App) error {
23+ if err := BackupDB(db, a); err != nil {
24+ return err
25+ }
26+
27+ if err := db.Close(); err != nil {
28+ return fmt.Errorf("failed to close database: %v", err)
29+ }
30+
31+ return nil
32+}
33+
34+// LoadDBIntoMemory loads the database from disk into memory
35+func LoadDBIntoMemory(a *App) (*sql.DB, error) {
36+ dbfp := a.GetDBFilePath()
37+
38+ if _, err := os.Stat(dbfp); err != nil {
39+ return nil, nil
40+ }
41+
42+ memDB, err := InitDB()
43+ if err != nil {
44+ return nil, err
45+ }
46+
47+ diskDB, err := sql.Open("sqlite3", dbfp)
48+ if err != nil {
49+ return nil, fmt.Errorf("failed to open database file: %v", err)
50+ }
51+
52+ if err := transferData(diskDB, memDB); err != nil {
53+ return nil, err
54+ }
55+
56+ return memDB, nil
57+}
58+
59+// transferData transfers data from srcDB to dstDB
60+func transferData(srcDB, dstDB *sql.DB) error {
61+ srcConn, err := srcDB.Conn(context.Background())
62+ if err != nil {
63+ return fmt.Errorf("failed to get connection from srcDB: %v", err)
64+ }
65+ defer srcConn.Close()
66+
67+ dstConn, err := dstDB.Conn(context.Background())
68+ if err != nil {
69+ return fmt.Errorf("failed to get connection from dstDB: %v", err)
70+ }
71+ defer dstConn.Close()
72+
73+ return srcConn.Raw(func(srcRawConn interface{}) error {
74+ return dstConn.Raw(func(dstRawConn interface{}) error {
75+ srcSqlite3Conn := srcRawConn.(*sqlite3.SQLiteConn)
76+ dstSqlite3Conn := dstRawConn.(*sqlite3.SQLiteConn)
77+
78+ _, err := srcSqlite3Conn.Backup("main", dstSqlite3Conn, "main")
79+ return err
80+ })
81+ })
82+}
83+
84+// BackupDB backs up the in-memory database to disk
85+func BackupDB(db *sql.DB, a *App) error {
86+ dbfp := a.GetDBFilePath()
87+
88+ conn, err := db.Conn(context.Background())
89+ if err != nil {
90+ return fmt.Errorf("failed to get underlying database connection: %v", err)
91+ }
92+
93+ return conn.Raw(func(sqliteConn interface{}) error {
94+ sqlite3Conn := sqliteConn.(*sqlite3.SQLiteConn)
95+ backupDB, err := sqlite3Conn.Backup(dbfp, sqlite3Conn, "main")
96+ if err != nil {
97+ return fmt.Errorf("failed to create backup: %v", err)
98+ }
99+ defer backupDB.Close()
100+
101+ _, err = backupDB.Step(-1)
102+ if err != nil {
103+ return fmt.Errorf("failed to backup in-memory database: %v", err)
104+ }
105+
106+ return nil
107+ })
108+}
@@ -0,0 +1,108 @@
1+package app
2+
3+import (
4+ "context"
5+ "database/sql"
6+ "fmt"
7+ "os"
8+
9+ sqlite3 "github.com/mattn/go-sqlite3"
10+)
11+
12+// Initialize in-memory SQLite database and returns its connection
13+func InitDB() (db *sql.DB, err error) {
14+ db, err = sql.Open("sqlite3", "file::memory?cache=shared")
15+ if err != nil {
16+ return nil, fmt.Errorf("failed to open in-memory database: %v", err)
17+ }
18+ return
19+}
20+
21+// CloseDB closes the database connection and backs up the in-memory database to disk
22+func CloseDB(db *sql.DB, a *App) error {
23+ if err := BackupDB(db, a); err != nil {
24+ return err
25+ }
26+
27+ if err := db.Close(); err != nil {
28+ return fmt.Errorf("failed to close database: %v", err)
29+ }
30+
31+ return nil
32+}
33+
34+// LoadDBIntoMemory loads the database from disk into memory
35+func LoadDBIntoMemory(a *App) (*sql.DB, error) {
36+ dbfp := a.GetDBFilePath()
37+
38+ if _, err := os.Stat(dbfp); err != nil {
39+ return nil, nil
40+ }
41+
42+ memDB, err := InitDB()
43+ if err != nil {
44+ return nil, err
45+ }
46+
47+ diskDB, err := sql.Open("sqlite3", dbfp)
48+ if err != nil {
49+ return nil, fmt.Errorf("failed to open database file: %v", err)
50+ }
51+
52+ if err := transferData(diskDB, memDB); err != nil {
53+ return nil, err
54+ }
55+
56+ return memDB, nil
57+}
58+
59+// transferData transfers data from srcDB to dstDB
60+func transferData(srcDB, dstDB *sql.DB) error {
61+ srcConn, err := srcDB.Conn(context.Background())
62+ if err != nil {
63+ return fmt.Errorf("failed to get connection from srcDB: %v", err)
64+ }
65+ defer srcConn.Close()
66+
67+ dstConn, err := dstDB.Conn(context.Background())
68+ if err != nil {
69+ return fmt.Errorf("failed to get connection from dstDB: %v", err)
70+ }
71+ defer dstConn.Close()
72+
73+ return srcConn.Raw(func(srcRawConn interface{}) error {
74+ return dstConn.Raw(func(dstRawConn interface{}) error {
75+ srcSqlite3Conn := srcRawConn.(*sqlite3.SQLiteConn)
76+ dstSqlite3Conn := dstRawConn.(*sqlite3.SQLiteConn)
77+
78+ _, err := srcSqlite3Conn.Backup("main", dstSqlite3Conn, "main")
79+ return err
80+ })
81+ })
82+}
83+
84+// BackupDB backs up the in-memory database to disk
85+func BackupDB(db *sql.DB, a *App) error {
86+ dbfp := a.GetDBFilePath()
87+
88+ conn, err := db.Conn(context.Background())
89+ if err != nil {
90+ return fmt.Errorf("failed to get underlying database connection: %v", err)
91+ }
92+
93+ return conn.Raw(func(sqliteConn interface{}) error {
94+ sqlite3Conn := sqliteConn.(*sqlite3.SQLiteConn)
95+ backupDB, err := sqlite3Conn.Backup(dbfp, sqlite3Conn, "main")
96+ if err != nil {
97+ return fmt.Errorf("failed to create backup: %v", err)
98+ }
99+ defer backupDB.Close()
100+
101+ _, err = backupDB.Step(-1)
102+ if err != nil {
103+ return fmt.Errorf("failed to backup in-memory database: %v", err)
104+ }
105+
106+ return nil
107+ })
108+}
M internal/gotemplate/render/html.go +7 -5
@@ -3,10 +3,10 @@ package render
33 import (
44 "bytes"
55 "fmt"
6+ "github.com/bnema/gordon/internal/app"
67 "html/template"
78 "io/fs"
8-
9- "github.com/bnema/gordon/internal/app"
9+ "path"
1010 )
1111
1212 type Renderer struct {
@@ -34,14 +34,16 @@ func (r *Renderer) Render(data interface{}, a *app.App) (string, error) {
3434 }
3535
3636 // GetRenderer function returns a new Renderer instance
37-func GetHTMLRenderer(filename string, fs fs.FS, a *app.App) (*Renderer, error) {
37+func GetHTMLRenderer(pathStr string, filename string, fs fs.FS, a *app.App) (*Renderer, error) {
38+ // Join path and filename
39+ fullPath := path.Join(pathStr, filename)
3840 // Check if the file exists in the provided fs.FS using fs.Open
39- file, err := fs.Open(filename)
41+ file, err := fs.Open(fullPath)
4042 if err != nil {
4143 return nil, fmt.Errorf("failed to open %s: %w", filename, err)
4244 }
4345 file.Close() // Close the file after checking
44- tmpl, err := template.New(filename).ParseFS(fs, filename)
46+ tmpl, err := template.New(filename).ParseFS(fs, fullPath)
4547 if err != nil {
4648 return nil, fmt.Errorf("failed to parse %s: %w", filename, err)
4749 }
@@ -3,10 +3,10 @@ package render
3 import (3 import (
4 "bytes"4 "bytes"
5 "fmt"5 "fmt"
6+ "github.com/bnema/gordon/internal/app"
6 "html/template"7 "html/template"
7 "io/fs"8 "io/fs"
8-9+ "path"
9- "github.com/bnema/gordon/internal/app"
10 )10 )
11 11
12 type Renderer struct {12 type Renderer struct {
@@ -34,14 +34,16 @@ func (r *Renderer) Render(data interface{}, a *app.App) (string, error) {
34 }34 }
35 35
36 // GetRenderer function returns a new Renderer instance36 // GetRenderer function returns a new Renderer instance
37-func GetHTMLRenderer(filename string, fs fs.FS, a *app.App) (*Renderer, error) {37+func GetHTMLRenderer(pathStr string, filename string, fs fs.FS, a *app.App) (*Renderer, error) {
38+ // Join path and filename
39+ fullPath := path.Join(pathStr, filename)
38 // Check if the file exists in the provided fs.FS using fs.Open40 // Check if the file exists in the provided fs.FS using fs.Open
39- file, err := fs.Open(filename)41+ file, err := fs.Open(fullPath)
40 if err != nil {42 if err != nil {
41 return nil, fmt.Errorf("failed to open %s: %w", filename, err)43 return nil, fmt.Errorf("failed to open %s: %w", filename, err)
42 }44 }
43 file.Close() // Close the file after checking45 file.Close() // Close the file after checking
44- tmpl, err := template.New(filename).ParseFS(fs, filename)46+ tmpl, err := template.New(filename).ParseFS(fs, fullPath)
45 if err != nil {47 if err != nil {
46 return nil, fmt.Errorf("failed to parse %s: %w", filename, err)48 return nil, fmt.Errorf("failed to parse %s: %w", filename, err)
47 }49 }
M internal/httpserve/handler/adminroutes.go +8 -10
@@ -13,24 +13,22 @@ import (
1313 // Handle the admin route to display index.gohtml from the templateFS with the data from strings.yml
1414 func AdminRoute(c echo.Context, a *app.App) error {
1515 lang := c.Get(middleware.LangKey).(string)
16- fmt.Println(lang)
17- data := webui.StringsYamlData{}
18- err := webui.ReadStringsDataFromYAML(lang, a.TemplateFS, "strings.yml", &data)
16+ yamlData := webui.StringsYamlData{}
17+ err := webui.ReadStringsDataFromYAML(lang, a.TemplateFS, "strings.yml", &yamlData)
1918 if err != nil {
20- return fmt.Errorf("failed to read strings data from YAML: %w", err)
19+ return err
2120 }
2221
2322 // Navigate inside the fs.FS to get the template
24-
25- rendererData, err := render.GetHTMLRenderer("html/admin/index.gohtml", a.TemplateFS, a)
23+ path := "html/admin"
24+ rendererData, err := render.GetHTMLRenderer(path, "index.gohtml", a.TemplateFS, a)
2625 if err != nil {
27- return fmt.Errorf("failed to get renderer: %w", err)
26+ return err
2827 }
2928
30- renderedHTML, err := rendererData.Render(data, a)
31- fmt.Println(renderedHTML)
29+ renderedHTML, err := rendererData.Render(yamlData.CurrentLang, a)
3230 if err != nil {
33- return fmt.Errorf("failed to render template: %w", err)
31+ return err
3432 }
3533
3634 return c.HTML(200, renderedHTML)
@@ -13,24 +13,22 @@ import (
13 // Handle the admin route to display index.gohtml from the templateFS with the data from strings.yml13 // Handle the admin route to display index.gohtml from the templateFS with the data from strings.yml
14 func AdminRoute(c echo.Context, a *app.App) error {14 func AdminRoute(c echo.Context, a *app.App) error {
15 lang := c.Get(middleware.LangKey).(string)15 lang := c.Get(middleware.LangKey).(string)
16- fmt.Println(lang)16+ yamlData := webui.StringsYamlData{}
17- data := webui.StringsYamlData{}17+ err := webui.ReadStringsDataFromYAML(lang, a.TemplateFS, "strings.yml", &yamlData)
18- err := webui.ReadStringsDataFromYAML(lang, a.TemplateFS, "strings.yml", &data)
19 if err != nil {18 if err != nil {
20- return fmt.Errorf("failed to read strings data from YAML: %w", err)19+ return err
21 }20 }
22 21
23 // Navigate inside the fs.FS to get the template22 // Navigate inside the fs.FS to get the template
24-23+ path := "html/admin"
25- rendererData, err := render.GetHTMLRenderer("html/admin/index.gohtml", a.TemplateFS, a)24+ rendererData, err := render.GetHTMLRenderer(path, "index.gohtml", a.TemplateFS, a)
26 if err != nil {25 if err != nil {
27- return fmt.Errorf("failed to get renderer: %w", err)26+ return err
28 }27 }
29 28
30- renderedHTML, err := rendererData.Render(data, a)29+ renderedHTML, err := rendererData.Render(yamlData.CurrentLang, a)
31- fmt.Println(renderedHTML)
32 if err != nil {30 if err != nil {
33- return fmt.Errorf("failed to render template: %w", err)31+ return err
34 }32 }
35 33
36 return c.HTML(200, renderedHTML)34 return c.HTML(200, renderedHTML)
A pkg/utils/docker/initclient.go +35 -0
@@ -0,0 +1,35 @@
1+package docker
2+
3+import (
4+ "context"
5+ "fmt"
6+ "log"
7+
8+ "github.com/bnema/gordon/internal/app"
9+ "github.com/docker/docker/api/types"
10+ "github.com/docker/docker/client"
11+ "github.com/docker/docker/pkg/archive"
12+)
13+
14+var dockerClient *client.Client
15+
16+func init() {
17+ // Get Docker configuration from App
18+ appInstance := app.NewDockerClient()
19+ dockerSocket := appInstance.DockerSock
20+ podmanEnable := appInstance.PodmanEnable
21+ podmanSocket := appInstance.PodmanSock
22+
23+ // Based on configuration, decide whether to use Docker or Podman
24+ socketPath := dockerSocket
25+ if podmanEnable {
26+ socketPath = podmanSocket
27+ }
28+
29+ // Initialize Docker client
30+ var err error
31+ dockerClient, err = client.NewClientWithOpts(client.WithHost(fmt.Sprintf("unix://%s", socketPath)), client.WithAPIVersionNegotiation())
32+ if err != nil {
33+ log.Fatalf("Error initializing Docker client: %v", err)
34+ }
35+}
@@ -0,0 +1,35 @@
1+package docker
2+
3+import (
4+ "context"
5+ "fmt"
6+ "log"
7+
8+ "github.com/bnema/gordon/internal/app"
9+ "github.com/docker/docker/api/types"
10+ "github.com/docker/docker/client"
11+ "github.com/docker/docker/pkg/archive"
12+)
13+
14+var dockerClient *client.Client
15+
16+func init() {
17+ // Get Docker configuration from App
18+ appInstance := app.NewDockerClient()
19+ dockerSocket := appInstance.DockerSock
20+ podmanEnable := appInstance.PodmanEnable
21+ podmanSocket := appInstance.PodmanSock
22+
23+ // Based on configuration, decide whether to use Docker or Podman
24+ socketPath := dockerSocket
25+ if podmanEnable {
26+ socketPath = podmanSocket
27+ }
28+
29+ // Initialize Docker client
30+ var err error
31+ dockerClient, err = client.NewClientWithOpts(client.WithHost(fmt.Sprintf("unix://%s", socketPath)), client.WithAPIVersionNegotiation())
32+ if err != nil {
33+ log.Fatalf("Error initializing Docker client: %v", err)
34+ }
35+}

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