blob: dae56f8983f361401632b7f3105b19ec60b06f8a [file] [log] [blame]
gio5e49bb62024-07-20 10:43:19 +04001package welcome
2
3import (
4 "fmt"
5 "io"
6 "io/fs"
7 "strings"
8 "text/template"
9
10 "github.com/giolekva/pcloud/core/installer"
11 "github.com/giolekva/pcloud/core/installer/soft"
12)
13
14const tmplSuffix = ".gotmpl"
15
16type AppTmplStore interface {
gio8fae3af2024-07-25 13:43:31 +040017 Types() []string
gio5e49bb62024-07-20 10:43:19 +040018 Find(appType string) (AppTmpl, error)
19}
20
21type appTmplStoreFS struct {
22 tmpls map[string]AppTmpl
23}
24
25func NewAppTmplStoreFS(fsys fs.FS) (AppTmplStore, error) {
26 entries, err := fs.ReadDir(fsys, ".")
27 if err != nil {
28 return nil, err
29 }
30 apps := map[string]AppTmpl{}
31 for _, e := range entries {
32 if !e.IsDir() {
33 continue
34 }
35 app, err := NewAppTmplFS(fsys, e.Name())
36 if err != nil {
37 return nil, err
38 }
39 apps[e.Name()] = app
40 }
41 return &appTmplStoreFS{apps}, nil
42}
43
gio8fae3af2024-07-25 13:43:31 +040044func (s *appTmplStoreFS) Types() []string {
45 var ret []string
46 for t := range s.tmpls {
47 ret = append(ret, t)
48 }
49 return ret
50}
51
gio5e49bb62024-07-20 10:43:19 +040052func (s *appTmplStoreFS) Find(appType string) (AppTmpl, error) {
53 if app, ok := s.tmpls[appType]; ok {
54 return app, nil
55 } else {
56 return nil, fmt.Errorf("not found")
57 }
58}
59
60type AppTmpl interface {
61 Render(network installer.Network, subdomain string, out soft.RepoFS) error
62}
63
64type appTmplFS struct {
65 files map[string][]byte
66 tmpls map[string]*template.Template
67}
68
69func NewAppTmplFS(fsys fs.FS, root string) (AppTmpl, error) {
70 files := map[string][]byte{}
71 tmpls := map[string]*template.Template{}
72 if err := fs.WalkDir(fsys, root, func(path string, d fs.DirEntry, err error) error {
73 if err != nil {
74 return err
75 }
76 if d.IsDir() {
77 return nil
78 }
79 contents, err := fs.ReadFile(fsys, path)
80 if err != nil {
81 return err
82 }
83 p, _ := strings.CutPrefix(path, root)
84 if !strings.HasSuffix(p, tmplSuffix) {
85 files[p] = contents
86 return nil
87 }
88 tmpl, err := template.New(path).Parse(string(contents))
89 if err != nil {
90 return err
91 }
92 np, _ := strings.CutSuffix(p, tmplSuffix)
93 tmpls[np] = tmpl
94 return nil
95 }); err != nil {
96 return nil, err
97 }
98 return &appTmplFS{files, tmpls}, nil
99}
100
101func (a *appTmplFS) Render(network installer.Network, subdomain string, out soft.RepoFS) error {
102 for path, tmpl := range a.tmpls {
103 f, err := out.Writer(path)
104 if err != nil {
105 return err
106 }
107 defer f.Close()
108 if err := tmpl.Execute(f, map[string]any{
109 "Network": network,
110 "Subdomain": subdomain,
111 }); err != nil {
112 return err
113 }
114 }
115 for path, contents := range a.files {
116 f, err := out.Writer(path)
117 if err != nil {
118 return err
119 }
120 defer f.Close()
121 if _, err := io.WriteString(f, string(contents)); err != nil {
122 return err
123 }
124 }
125 return nil
126}