GitRoot
Craft your forge, Build your project, Grow your community freely
1// SPDX-FileCopyrightText: 2025 Romain Maneschi <romain@gitroot.dev>
2//
3// SPDX-License-Identifier: EUPL-1.2
4
5package main
6
7import (
8 "fmt"
9
10 "github.com/tidwall/gjson"
11 "gitroot.dev/libs/golang/glob"
12 gitroot "gitroot.dev/libs/golang/plugin/model"
13)
14
15type conf struct {
16 defaultBranch string
17 language string
18 style string
19 favicon string
20 header string
21 menu []link
22 footer string
23 generateGitWorktree bool
24 branchesDir string
25 meta map[string]string
26 layout []layout
27}
28
29var defaultRun = []gitroot.PluginRun{{
30 Path: "**/*",
31 Branch: []string{"main"},
32 When: gitroot.PluginRunWhenAll,
33 Func: []gitroot.PluginFunc{{FuncName: "renderHtml", Args: []string{"fp", "html", "extraMedata"}, Res: []string{"html"}}},
34 Write: gitroot.PluginWrite{
35 Git: []gitroot.PluginWriteRight{{
36 Path: "index.md",
37 Can: []gitroot.PluginWriteRightCan{gitroot.PluginWriteRightCanAdd},
38 }},
39 Web: []gitroot.PluginWriteRight{{
40 Path: "**/*",
41 Can: gitroot.PluginWriteRightCanAll,
42 }},
43 Exec: []gitroot.PluginExecRight{},
44 CallFunc: []gitroot.PluginCallFuncRight{
45 {PluginPURL: PLUGIN_MARKDOWN, FuncName: PLUGIN_MARKDOWN_FUNC, Configuration: map[string]any{}},
46 {PluginPURL: PLUGIN_CODE, FuncName: PLUGIN_CODE_FUNC, Configuration: map[string]any{}},
47 {PluginPURL: PLUGIN_MERMAID, FuncName: PLUGIN_MERMAID_FUNC, Configuration: map[string]any{}}, //TODO it's transitive how to not do this? It's needed because runtime check that plugin can call that other l.785 runtime.go::CallBuilder()
48 },
49 },
50 Configuration: map[string]any{
51 "defaultBranch": "main",
52 "language": "en",
53 "style": "simple.min.css",
54 "favicon": "icon.png",
55 "header": "<h1>{{repo.name}}</h1>",
56 "menu": []link{
57 {Display: "🏠 Home", Link: "/"},
58 {Display: "📖 Readme", Link: "/README.html"},
59 {Display: "🐞 Issues", Link: "/boards/issues.html"},
60 {Display: "⚖ Licence", Link: "/LICENCE.html"},
61 },
62 "footer": "<p>Clone with <code>git clone {{repo.cloneUrl}}</code></p><small>Hosted with ❤️ by <a href=\"https://gitroot.dev\">GitRoot</a></small>",
63 "generateGitWorktree": true,
64 "branchesDir": "branches",
65 "meta": map[string]string{
66 "description": "a short description",
67 "og:title": "title displayed in social",
68 "og:description": "description displayed in social",
69 "og:type": "article",
70 "fediverse:creator": "@forge@gitroot.dev",
71 },
72 "layout": []layout{},
73 },
74}, {
75 Path: "**/*",
76 Branch: []string{"*", "!main"},
77 When: gitroot.PluginRunWhenAll,
78 Func: []gitroot.PluginFunc{},
79 Write: gitroot.PluginWrite{
80 Git: []gitroot.PluginWriteRight{},
81 Web: []gitroot.PluginWriteRight{{
82 Path: "branches/**/*",
83 Can: gitroot.PluginWriteRightCanAll,
84 }},
85 Exec: []gitroot.PluginExecRight{},
86 CallFunc: []gitroot.PluginCallFuncRight{
87 {PluginPURL: PLUGIN_MARKDOWN, FuncName: PLUGIN_MARKDOWN_FUNC, Configuration: map[string]any{}},
88 {PluginPURL: PLUGIN_CODE, FuncName: PLUGIN_CODE_FUNC, Configuration: map[string]any{}},
89 {PluginPURL: PLUGIN_MERMAID, FuncName: PLUGIN_MERMAID_FUNC, Configuration: map[string]any{}}, //TODO it's transitive how to not do this? It's needed because runtime check that plugin can call that other l.785 runtime.go::CallBuilder()
90 },
91 },
92 Configuration: map[string]any{
93 "defaultBranch": "main",
94 "language": "en",
95 "style": "simple.min.css",
96 "favicon": "icon.png",
97 "header": "<h1>{{repo.name}}</h1>",
98 "menu": []link{
99 {Display: "🏠 Home", Link: "/"},
100 {Display: "📖 Readme", Link: "/README.html"},
101 {Display: "🐞 Issues", Link: "/boards/issues.html"},
102 {Display: "⚖ Licence", Link: "/LICENCE.html"},
103 },
104 "footer": "<p>Clone with <code>git clone {{repo.cloneUrl}}</code></p><small>Hosted with ❤️ by <a href=\"https://gitroot.dev\">GitRoot</a></small>",
105 "generateGitWorktree": false,
106 "branchesDir": "branches",
107 "meta": map[string]string{
108 "description": "a short description",
109 "og:title": "title displayed in social",
110 "og:description": "description displayed in social",
111 "og:type": "article",
112 "fediverse:creator": "@forge@gitroot.dev",
113 },
114 "layout": []layout{},
115 },
116}}
117
118type link struct {
119 Link string `json:"link"`
120 Display string `json:"display"`
121}
122
123type layout struct {
124 Glob *glob.Glob `json:"glob"`
125 Path string `json:"path"`
126}
127
128func (p *Plugin) newConf(serializedConf string) *conf {
129 jsonConf := gjson.Parse(serializedConf)
130 menus := []link{}
131 for _, l := range jsonConf.Get("menu").Array() {
132 menus = append(menus, link{
133 Link: l.Get("link").String(),
134 Display: l.Get("display").String(),
135 })
136 }
137 layouts := []layout{}
138 for _, ljson := range jsonConf.Get("layout").Array() {
139 l := ljson.Get("glob").String()
140 if g, err := glob.NewGlob(l); err == nil {
141 layouts = append(layouts, layout{
142 Glob: g,
143 Path: ljson.Get("path").String(),
144 })
145 } else {
146 p.server.LogError(fmt.Sprintf("bad glob ignore layout %s", l), err)
147 }
148 }
149 metaJson := jsonConf.Get("meta").Map()
150 meta := make(map[string]string, len(metaJson))
151 for key, val := range metaJson {
152 meta[key] = val.String()
153 }
154 defaultBranch := jsonConf.Get("defaultBranch").String()
155 if defaultBranch == "" {
156 defaultBranch = "main"
157 }
158 style := jsonConf.Get("style").String()
159 if style == "" {
160 style = "simple.min.css"
161 }
162 lang := jsonConf.Get("language").String()
163 if lang == "" {
164 lang = "en"
165 }
166 return &conf{
167 defaultBranch: defaultBranch,
168 language: lang,
169 style: style,
170 favicon: jsonConf.Get("favicon").String(),
171 header: jsonConf.Get("header").String(),
172 menu: menus,
173 footer: jsonConf.Get("footer").String(),
174 generateGitWorktree: jsonConf.Get("generateGitWorktree").Bool(),
175 branchesDir: jsonConf.Get("branchesDir").String(),
176 meta: meta,
177 layout: layouts,
178 }
179}