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: MIT
4
5package gitroot
6
7// #include <stdlib.h>
8import "C"
9
10import (
11 "encoding/json"
12 "errors"
13 "io/fs"
14 "os"
15 "runtime"
16
17 "github.com/tidwall/gjson"
18 "gitroot.dev/libs/golang/plugin/model"
19)
20
21type PluginFactory = func(server model.Server) model.Plugin
22
23type pServer struct {
24 plugin model.Plugin
25 pluginOpts model.PluginOption
26 run []model.PluginRun
27 atLeastOneChange bool
28}
29
30var server = &pServer{
31 atLeastOneChange: false,
32 pluginOpts: model.PluginOption{},
33}
34
35func Register(run []model.PluginRun, p PluginFactory) {
36 server.run = run
37 server.plugin = p(server)
38}
39
40func (s *pServer) PluginOption(opts ...model.PluginOptionWith) {
41 for _, opt := range opts {
42 server.pluginOpts = opt(server.pluginOpts)
43 }
44}
45
46func (s *pServer) ForgeConf() (model.ForgeConf, error) {
47 forgeConf := model.ForgeConf{}
48 ptrSize := _forgeConf()
49 if ptrSize == 0 {
50 return forgeConf, errors.New("can't make diff")
51 }
52 ptrDiff := uint32(ptrSize >> 32)
53 sizeDiff := uint32(ptrSize)
54 forgeConfJson := gjson.Parse(ptrToString(ptrDiff, sizeDiff))
55 return model.ForgeConf{
56 Domain: forgeConfJson.Get("domain").String(),
57 ExternalSshAddr: forgeConfJson.Get("externalSshAddr").String(),
58 ExternalHttpAddr: forgeConfJson.Get("externalHttpAddr").String(),
59 }, nil
60}
61
62func (s *pServer) Worktree() fs.FS {
63 return os.DirFS("/worktree")
64}
65
66func (s *pServer) Webcontent() fs.FS {
67 return os.DirFS("/webcontent")
68}
69
70func (s *pServer) Cache() fs.FS {
71 return os.DirFS("/cache")
72}
73
74func (s *pServer) ModifyContent(filepath, content string) {
75 s.atLeastOneChange = true
76 ptr, size := stringToPtr(filepath)
77 ptr2, size2 := stringToPtr(content)
78 _modifyContent(ptr, size, ptr2, size2)
79 runtime.KeepAlive(filepath)
80 runtime.KeepAlive(content)
81}
82
83func (s *pServer) ModifyWebContent(filepath, content string) {
84 ptr, size := stringToPtr(filepath)
85 ptr2, size2 := stringToPtr(content)
86 _modifyWebContent(ptr, size, ptr2, size2)
87 runtime.KeepAlive(filepath)
88 runtime.KeepAlive(content)
89}
90
91func (s *pServer) ReplaceWebContent(filepath, oldContent, content string) {
92 ptr, size := stringToPtr(filepath)
93 ptr2, size2 := stringToPtr(oldContent)
94 ptr3, size3 := stringToPtr(content)
95 _replaceWebContent(ptr, size, ptr2, size2, ptr3, size3)
96 runtime.KeepAlive(filepath)
97 runtime.KeepAlive(oldContent)
98 runtime.KeepAlive(content)
99}
100
101func (s *pServer) ModifyCacheContent(filepath, content string) {
102 ptr, size := stringToPtr(filepath)
103 ptr2, size2 := stringToPtr(content)
104 _modifyCacheContent(ptr, size, ptr2, size2)
105 runtime.KeepAlive(filepath)
106 runtime.KeepAlive(content)
107}
108
109func (s *pServer) CommitAllIfNeeded(message string) {
110 if s.atLeastOneChange {
111 ptr, size := stringToPtr(message)
112 _commitAll(ptr, size)
113 runtime.KeepAlive(message)
114 }
115}
116
117func (s *pServer) DiffWithParent(hash string, oldFilepath string, newFilePath string) (string, error) {
118 ptrHash, sizeHash := stringToPtr(hash)
119 ptrOldFile, sizeOldFile := stringToPtr(oldFilepath)
120 ptrNewFile, sizeNewFile := stringToPtr(newFilePath)
121 ptrSizeDiff := _diffWithParent(ptrHash, sizeHash, ptrOldFile, sizeOldFile, ptrNewFile, sizeNewFile)
122 if ptrSizeDiff == 0 {
123 return "", errors.New("can't make diff")
124 }
125 ptrDiff := uint32(ptrSizeDiff >> 32)
126 sizeDiff := uint32(ptrSizeDiff)
127 return ptrToString(ptrDiff, sizeDiff), nil
128}
129
130func (s *pServer) Log(message string) {
131 ptr, size := stringToPtr(message)
132 _log(ptr, size)
133 runtime.KeepAlive(message)
134}
135
136func (s *pServer) LogError(message string, err error) {
137 ptr, size := stringToPtr(message)
138 errPtr, errSize := stringToPtr(err.Error())
139 _logError(ptr, size, errPtr, errSize)
140 runtime.KeepAlive(message)
141 runtime.KeepAlive(err)
142}
143
144func (s *pServer) Merge(from string, to string) {
145 fromPtr, fromSize := stringToPtr(from)
146 toPtr, toSize := stringToPtr(to)
147 _merge(fromPtr, fromSize, toPtr, toSize)
148 runtime.KeepAlive(from)
149 runtime.KeepAlive(to)
150}
151
152func (s *pServer) Commits(from string, to string) ([]model.Commit, error) {
153 fromPtr, fromSize := stringToPtr(from)
154 toPtr, toSize := stringToPtr(to)
155 ptrSizeDiff := _commits(fromPtr, fromSize, toPtr, toSize)
156 runtime.KeepAlive(from)
157 runtime.KeepAlive(to)
158 if ptrSizeDiff == 0 {
159 return nil, errors.New("can't get commits")
160 }
161 ptrDiff := uint32(ptrSizeDiff >> 32)
162 sizeDiff := uint32(ptrSizeDiff)
163 return model.CommitsFromString(ptrToString(ptrDiff, sizeDiff)), nil
164}
165
166func (s *pServer) Exec(exec model.Exec) (model.ExecStatus, error) {
167 execMarshalled, err := json.Marshal(exec)
168 if err != nil {
169 return model.ExecStatus{}, err
170 }
171 ptr, size := stringToPtr(string(execMarshalled))
172 ptrSize := _exec(ptr, size)
173 if ptrSize == 0 {
174 return model.ExecStatus{}, errors.New("can't exec")
175 }
176 ptrLog := uint32(ptrSize >> 32)
177 sizeLog := uint32(ptrSize)
178 return model.ExecStatusFromString(ptrToString(ptrLog, sizeLog)), nil
179}
180
181func (s *pServer) ReportToPlugin(report model.Report) {
182 if s.pluginOpts.Reporter != nil {
183 if err := s.pluginOpts.Reporter(report); err != nil {
184 s.LogError("plugin reporter err", err)
185 }
186 }
187}
188
189func (s *pServer) Report(level model.ReportLevel, content []string) error {
190 reportMarshalled, err := json.Marshal(model.ReportToGitroot{Level: level, Content: content})
191 if err != nil {
192 return err
193 }
194 ptr, size := stringToPtr(string(reportMarshalled))
195 _report(ptr, size)
196 return nil
197}