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 "strings"
17 "time"
18 "unsafe"
19)
20
21type PluginFactory = func(server Server) Plugin
22
23type Commit struct {
24 Branch string
25 Hash string
26 Message string
27 Date time.Time
28}
29
30type Plugin interface {
31 Init(repoName string, confHasChanged bool, serializedConf string) error
32 StartCommit(commit Commit) error
33 AddFile(path string) error
34 ModFile(fromPath string, toPath string) error
35 DelFile(path string) error
36 EndCommit(commit Commit) error
37 Finish() error
38}
39
40type Server interface {
41 Worktree() fs.FS
42 Webcontent() fs.FS
43 Cache() fs.FS
44 ModifyContent(filepath, content string)
45 ModifyWebContent(filepath, content string)
46 ModifyCacheContent(filepath, content string)
47 CommitAllIfNeeded(message string)
48 DiffWithParent(file string, hash string) (string, error)
49 Log(message string)
50 LogError(message string, err error)
51 Merge(from string, to string)
52}
53
54type pServer struct {
55 plugin Plugin
56 run string
57 atLeastOneChange bool
58}
59
60var server = &pServer{
61 atLeastOneChange: false,
62}
63
64func Register(run []PluginRun, p PluginFactory) {
65 if j, err := json.Marshal(run); err == nil {
66 server.run = string(j)
67 } else {
68 server.LogError("can't marshal conf", err)
69 }
70 server.plugin = p(server)
71}
72
73func (s *pServer) Worktree() fs.FS {
74 return os.DirFS("/worktree")
75}
76
77func (s *pServer) Webcontent() fs.FS {
78 return os.DirFS("/webcontent")
79}
80
81func (s *pServer) Cache() fs.FS {
82 return os.DirFS("/cache")
83}
84
85func (s *pServer) ModifyContent(filepath, content string) {
86 s.atLeastOneChange = true
87 ptr, size := stringToPtr(filepath)
88 ptr2, size2 := stringToPtr(content)
89 _modifyContent(ptr, size, ptr2, size2)
90 runtime.KeepAlive(filepath)
91 runtime.KeepAlive(content)
92}
93
94func (s *pServer) ModifyWebContent(filepath, content string) {
95 ptr, size := stringToPtr(filepath)
96 ptr2, size2 := stringToPtr(content)
97 _modifyWebContent(ptr, size, ptr2, size2)
98 runtime.KeepAlive(filepath)
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(file string, hash string) (string, error) {
119 ptrFile, sizeFile := stringToPtr(file)
120 ptrHash, sizeHash := stringToPtr(hash)
121 ptrDiff := uint32(uintptr(unsafe.Pointer(unsafe.StringData(strings.Repeat("?", 2048))))) // TODO only 2048 chars, find better way
122 sizeDiff := _diffWithParent(ptrFile, sizeFile, ptrHash, sizeHash, ptrDiff)
123 if sizeDiff == 0 {
124 return "", errors.New("can't make diff")
125 }
126 return ptrToString(ptrDiff, sizeDiff), nil
127}
128
129func (s *pServer) Log(message string) {
130 ptr, size := stringToPtr(message)
131 _log(ptr, size)
132 runtime.KeepAlive(message)
133}
134
135func (s *pServer) LogError(message string, err error) {
136 ptr, size := stringToPtr(message)
137 errPtr, errSize := stringToPtr(err.Error())
138 _logError(ptr, size, errPtr, errSize)
139 runtime.KeepAlive(message)
140 runtime.KeepAlive(err)
141}
142
143func (s *pServer) Merge(from string, to string) {
144 fromPtr, fromSize := stringToPtr(from)
145 toPtr, toSize := stringToPtr(to)
146 _merge(fromPtr, fromSize, toPtr, toSize)
147 runtime.KeepAlive(from)
148 runtime.KeepAlive(to)
149}