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}