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 RootRepositoryName: forgeConfJson.Get("rootRepositoryName").String(),
60 }, nil
61}
62
63func (s *pServer) Worktree() fs.FS {
64 return os.DirFS("/worktree")
65}
66
67func (s *pServer) Webcontent() fs.FS {
68 return os.DirFS("/webcontent")
69}
70
71func (s *pServer) Cache() fs.FS {
72 return os.DirFS("/cache")
73}
74
75func (s *pServer) ModifyContent(filepath, content string) {
76 s.atLeastOneChange = true
77 ptr, size := stringToPtr(filepath)
78 ptr2, size2 := stringToPtr(content)
79 _modifyContent(ptr, size, ptr2, size2)
80 runtime.KeepAlive(filepath)
81 runtime.KeepAlive(content)
82}
83
84func (s *pServer) ModifyWebContent(filepath, content string) {
85 ptr, size := stringToPtr(filepath)
86 ptr2, size2 := stringToPtr(content)
87 _modifyWebContent(ptr, size, ptr2, size2)
88 runtime.KeepAlive(filepath)
89 runtime.KeepAlive(content)
90}
91
92func (s *pServer) ReplaceWebContent(filepath, oldContent, content string) {
93 ptr, size := stringToPtr(filepath)
94 ptr2, size2 := stringToPtr(oldContent)
95 ptr3, size3 := stringToPtr(content)
96 _replaceWebContent(ptr, size, ptr2, size2, ptr3, size3)
97 runtime.KeepAlive(filepath)
98 runtime.KeepAlive(oldContent)
99 runtime.KeepAlive(content)
100}
101
102func (s *pServer) ModifyCacheContent(filepath, content string) {
103 ptr, size := stringToPtr(filepath)
104 ptr2, size2 := stringToPtr(content)
105 _modifyCacheContent(ptr, size, ptr2, size2)
106 runtime.KeepAlive(filepath)
107 runtime.KeepAlive(content)
108}
109
110func (s *pServer) CommitAllIfNeeded(message string) {
111 if s.atLeastOneChange {
112 ptr, size := stringToPtr(message)
113 _commitAll(ptr, size)
114 runtime.KeepAlive(message)
115 }
116}
117
118func (s *pServer) DiffWithParent(hash string, oldFilepath string, newFilePath string) (string, error) {
119 ptrHash, sizeHash := stringToPtr(hash)
120 ptrOldFile, sizeOldFile := stringToPtr(oldFilepath)
121 ptrNewFile, sizeNewFile := stringToPtr(newFilePath)
122 ptrSizeDiff := _diffWithParent(ptrHash, sizeHash, ptrOldFile, sizeOldFile, ptrNewFile, sizeNewFile)
123 if ptrSizeDiff == 0 {
124 return "", errors.New("can't make diff")
125 }
126 ptrDiff := uint32(ptrSizeDiff >> 32)
127 sizeDiff := uint32(ptrSizeDiff)
128 return ptrToString(ptrDiff, sizeDiff), nil
129}
130
131func (s *pServer) Log(message string) {
132 ptr, size := stringToPtr(message)
133 _log(ptr, size)
134 runtime.KeepAlive(message)
135}
136
137func (s *pServer) LogError(message string, err error) {
138 ptr, size := stringToPtr(message)
139 errPtr, errSize := stringToPtr(err.Error())
140 _logError(ptr, size, errPtr, errSize)
141 runtime.KeepAlive(message)
142 runtime.KeepAlive(err)
143}
144
145func (s *pServer) Merge(from string, to string) {
146 fromPtr, fromSize := stringToPtr(from)
147 toPtr, toSize := stringToPtr(to)
148 _merge(fromPtr, fromSize, toPtr, toSize)
149 runtime.KeepAlive(from)
150 runtime.KeepAlive(to)
151}
152
153func (s *pServer) Commits(from string, to string) ([]model.Commit, error) {
154 fromPtr, fromSize := stringToPtr(from)
155 toPtr, toSize := stringToPtr(to)
156 ptrSizeDiff := _commits(fromPtr, fromSize, toPtr, toSize)
157 runtime.KeepAlive(from)
158 runtime.KeepAlive(to)
159 if ptrSizeDiff == 0 {
160 return nil, errors.New("can't get commits")
161 }
162 ptrDiff := uint32(ptrSizeDiff >> 32)
163 sizeDiff := uint32(ptrSizeDiff)
164 return model.CommitsFromString(ptrToString(ptrDiff, sizeDiff)), nil
165}
166
167func (s *pServer) Exec(exec model.Exec) (model.ExecStatus, error) {
168 execMarshalled, err := json.Marshal(exec)
169 if err != nil {
170 return model.ExecStatus{}, err
171 }
172 ptr, size := stringToPtr(string(execMarshalled))
173 ptrSize := _exec(ptr, size)
174 if ptrSize == 0 {
175 return model.ExecStatus{}, errors.New("can't exec")
176 }
177 ptrLog := uint32(ptrSize >> 32)
178 sizeLog := uint32(ptrSize)
179 return model.ExecStatusFromString(ptrToString(ptrLog, sizeLog)), nil
180}
181
182func (s *pServer) ReportToPlugin(report model.Report) {
183 if s.pluginOpts.Reporter != nil {
184 if err := s.pluginOpts.Reporter(report); err != nil {
185 s.LogError("plugin reporter err", err)
186 }
187 }
188}
189
190func (s *pServer) Report(level model.ReportLevel, content []string) error {
191 reportMarshalled, err := json.Marshal(model.ReportToGitroot{Level: level, Content: content})
192 if err != nil {
193 return err
194 }
195 ptr, size := stringToPtr(string(reportMarshalled))
196 _report(ptr, size)
197 return nil
198}