blob: 252d431772d7821d78d96d513c6bf12e94bffa19 [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 {
17 Find(appType string) (AppTmpl, error)
18}
19
20type appTmplStoreFS struct {
21 tmpls map[string]AppTmpl
22}
23
24func NewAppTmplStoreFS(fsys fs.FS) (AppTmplStore, error) {
25 entries, err := fs.ReadDir(fsys, ".")
26 if err != nil {
27 return nil, err
28 }
29 apps := map[string]AppTmpl{}
30 for _, e := range entries {
31 if !e.IsDir() {
32 continue
33 }
34 app, err := NewAppTmplFS(fsys, e.Name())
35 if err != nil {
36 return nil, err
37 }
38 apps[e.Name()] = app
39 }
40 return &appTmplStoreFS{apps}, nil
41}
42
43func (s *appTmplStoreFS) Find(appType string) (AppTmpl, error) {
44 if app, ok := s.tmpls[appType]; ok {
45 return app, nil
46 } else {
47 return nil, fmt.Errorf("not found")
48 }
49}
50
51type AppTmpl interface {
52 Render(network installer.Network, subdomain string, out soft.RepoFS) error
53}
54
55type appTmplFS struct {
56 files map[string][]byte
57 tmpls map[string]*template.Template
58}
59
60func NewAppTmplFS(fsys fs.FS, root string) (AppTmpl, error) {
61 files := map[string][]byte{}
62 tmpls := map[string]*template.Template{}
63 if err := fs.WalkDir(fsys, root, func(path string, d fs.DirEntry, err error) error {
64 if err != nil {
65 return err
66 }
67 if d.IsDir() {
68 return nil
69 }
70 contents, err := fs.ReadFile(fsys, path)
71 if err != nil {
72 return err
73 }
74 p, _ := strings.CutPrefix(path, root)
75 if !strings.HasSuffix(p, tmplSuffix) {
76 files[p] = contents
77 return nil
78 }
79 tmpl, err := template.New(path).Parse(string(contents))
80 if err != nil {
81 return err
82 }
83 np, _ := strings.CutSuffix(p, tmplSuffix)
84 tmpls[np] = tmpl
85 return nil
86 }); err != nil {
87 return nil, err
88 }
89 return &appTmplFS{files, tmpls}, nil
90}
91
92func (a *appTmplFS) Render(network installer.Network, subdomain string, out soft.RepoFS) error {
93 for path, tmpl := range a.tmpls {
94 f, err := out.Writer(path)
95 if err != nil {
96 return err
97 }
98 defer f.Close()
99 if err := tmpl.Execute(f, map[string]any{
100 "Network": network,
101 "Subdomain": subdomain,
102 }); err != nil {
103 return err
104 }
105 }
106 for path, contents := range a.files {
107 f, err := out.Writer(path)
108 if err != nil {
109 return err
110 }
111 defer f.Close()
112 if _, err := io.WriteString(f, string(contents)); err != nil {
113 return err
114 }
115 }
116 return nil
117}