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 Server) Plugin
22
23type Plugin interface {
24 Init(repoName string, confHasChanged bool, serializedConf string) error
25 StartCommit(commit model.Commit) error
26 AddFile(path string) error
27 ModFile(fromPath string, toPath string) error
28 DelFile(path string) error
29 EndCommit(commit model.Commit) error
30 Finish() error
31}
32
33type Server interface {
34 Worktree() fs.FS
35 Webcontent() fs.FS
36 Cache() fs.FS
37 ModifyContent(filepath, content string)
38 ModifyWebContent(filepath, content string)
39 ModifyCacheContent(filepath, content string)
40 CommitAllIfNeeded(message string)
41 DiffWithParent(hash string, oldFilepath string, newFilepath string) (string, error)
42 Log(message string)
43 LogError(message string, err error)
44 Merge(from string, to string)
45 Commits(from string, to string) ([]model.Commit, error)
46}
47
48type pServer struct {
49 plugin Plugin
50 run string
51 atLeastOneChange bool
52}
53
54var server = &pServer{
55 atLeastOneChange: false,
56}
57
58func Register(run []model.PluginRun, p PluginFactory) {
59 if j, err := json.Marshal(run); err == nil {
60 server.run = string(j)
61 } else {
62 server.LogError("can't marshal conf", err)
63 }
64 server.plugin = p(server)
65}
66
67func (s *pServer) Worktree() fs.FS {
68 return os.DirFS("/worktree")
69}
70
71func (s *pServer) Webcontent() fs.FS {
72 return os.DirFS("/webcontent")
73}
74
75func (s *pServer) Cache() fs.FS {
76 return os.DirFS("/cache")
77}
78
79func (s *pServer) ModifyContent(filepath, content string) {
80 s.atLeastOneChange = true
81 ptr, size := stringToPtr(filepath)
82 ptr2, size2 := stringToPtr(content)
83 _modifyContent(ptr, size, ptr2, size2)
84 runtime.KeepAlive(filepath)
85 runtime.KeepAlive(content)
86}
87
88func (s *pServer) ModifyWebContent(filepath, content string) {
89 ptr, size := stringToPtr(filepath)
90 ptr2, size2 := stringToPtr(content)
91 _modifyWebContent(ptr, size, ptr2, size2)
92 runtime.KeepAlive(filepath)
93 runtime.KeepAlive(content)
94}
95
96func (s *pServer) ModifyCacheContent(filepath, content string) {
97 ptr, size := stringToPtr(filepath)
98 ptr2, size2 := stringToPtr(content)
99 _modifyCacheContent(ptr, size, ptr2, size2)
100 runtime.KeepAlive(filepath)
101 runtime.KeepAlive(content)
102}
103
104func (s *pServer) CommitAllIfNeeded(message string) {
105 if s.atLeastOneChange {
106 ptr, size := stringToPtr(message)
107 _commitAll(ptr, size)
108 runtime.KeepAlive(message)
109 }
110}
111
112func (s *pServer) DiffWithParent(hash string, oldFilepath string, newFilePath string) (string, error) {
113 ptrHash, sizeHash := stringToPtr(hash)
114 ptrOldFile, sizeOldFile := stringToPtr(oldFilepath)
115 ptrNewFile, sizeNewFile := stringToPtr(newFilePath)
116 ptrSizeDiff := _diffWithParent(ptrHash, sizeHash, ptrOldFile, sizeOldFile, ptrNewFile, sizeNewFile)
117 if ptrSizeDiff == 0 {
118 return "", errors.New("can't make diff")
119 }
120 ptrDiff := uint32(ptrSizeDiff >> 32)
121 sizeDiff := uint32(ptrSizeDiff)
122 return ptrToString(ptrDiff, sizeDiff), nil
123}
124
125func (s *pServer) Log(message string) {
126 ptr, size := stringToPtr(message)
127 _log(ptr, size)
128 runtime.KeepAlive(message)
129}
130
131func (s *pServer) LogError(message string, err error) {
132 ptr, size := stringToPtr(message)
133 errPtr, errSize := stringToPtr(err.Error())
134 _logError(ptr, size, errPtr, errSize)
135 runtime.KeepAlive(message)
136 runtime.KeepAlive(err)
137}
138
139func (s *pServer) Merge(from string, to string) {
140 fromPtr, fromSize := stringToPtr(from)
141 toPtr, toSize := stringToPtr(to)
142 _merge(fromPtr, fromSize, toPtr, toSize)
143 runtime.KeepAlive(from)
144 runtime.KeepAlive(to)
145}
146
147func (s *pServer) Commits(from string, to string) ([]model.Commit, error) {
148 fromPtr, fromSize := stringToPtr(from)
149 toPtr, toSize := stringToPtr(to)
150 ptrSizeDiff := _commits(fromPtr, fromSize, toPtr, toSize)
151 runtime.KeepAlive(from)
152 runtime.KeepAlive(to)
153 if ptrSizeDiff == 0 {
154 return nil, errors.New("can't get commits")
155 }
156 ptrDiff := uint32(ptrSizeDiff >> 32)
157 sizeDiff := uint32(ptrSizeDiff)
158 jsonCommits := gjson.Parse(ptrToString(ptrDiff, sizeDiff)).Array()
159 res := make([]model.Commit, len(jsonCommits))
160 for i, jsonCommit := range jsonCommits {
161 res[i] = model.Commit{
162 Branch: jsonCommit.Get("Branch").String(),
163 Hash: jsonCommit.Get("Hash").String(),
164 Message: jsonCommit.Get("Message").String(),
165 Date: jsonCommit.Get("Date").Time(),
166 Committer: jsonCommit.Get("Committer").String(),
167 ParentHash: jsonCommit.Get("ParentHash").String(),
168 }
169 }
170 return res, nil
171}