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: EUPL-1.2
4
5package plugin
6
7import (
8 "context"
9 "fmt"
10 "io/fs"
11 "slices"
12 "strings"
13
14 "github.com/go-git/go-git/v5/plumbing"
15 pluginLib "gitroot.dev/libs/golang/plugin/model"
16 "gitroot.dev/server/logger"
17 "gitroot.dev/server/repository"
18)
19
20func (r *runtime) worktree(ctx context.Context, repo *repository.GitRootRepository, repoWriter *repository.GitRootRepositoryWrite, plugins []Plugin, cmds []CommandForDiff) error {
21 r.repo = repo
22 r.repoWriter = repoWriter
23 r.command = &cmds[len(cmds)-1] // TODO should not be last cmd see ./manager.go line 65 todo
24
25 filepaths := []string{}
26 fs.WalkDir(repoWriter.ToFs(ctx), ".", func(path string, d fs.DirEntry, err error) error {
27 if !d.IsDir() {
28 filepaths = append(filepaths, path)
29 }
30 return nil
31 })
32 commands, err := repo.GetLastCommits(filepaths)
33 if err != nil {
34 return err
35 }
36 slices.Reverse(commands)
37
38 r.commitHook = func(hash plumbing.Hash) {
39 command, err := repoWriter.GetLastCommit(hash)
40 if err != nil {
41 r.logger.Error("can't GetLastCommit", err)
42 return
43 }
44 commands = append(commands, command)
45 }
46 defer func() {
47 r.commitHook = nil
48 }()
49
50 for _, plugin := range plugins {
51 r.plugin = plugin
52 timerStop := r.logger.Time(fmt.Sprintf("Timer %s", plugin.Name))
53
54 r.logger.Debug("start plugin worktree", logger.NewLoggerPair("name", plugin.Name))
55 m, err := r.loadModule(ctx, plugin)
56 if err != nil {
57 r.logger.Error("loadModule for worktree error", err, logger.NewLoggerPair("name", plugin.Name))
58 continue
59 }
60 l := logger.NewLogger(logger.WASM)
61 l.Debug("memory before worktree", logger.NewLoggerPair("size", m.Memory().Size()), logger.NewLoggerPair("plugin", plugin.Name))
62 startCommit := m.ExportedFunction("startCommit")
63 endCommit := m.ExportedFunction("endCommit")
64 addFile := m.ExportedFunction("addFile")
65 malloc := m.ExportedFunction("gitrootAlloc")
66 if malloc == nil {
67 malloc = m.ExportedFunction("malloc")
68 }
69 free := m.ExportedFunction("gitrootFree")
70 if free == nil {
71 free = m.ExportedFunction("free")
72 }
73
74 for _, pluginRun := range plugin.Run {
75 isAuthorized := checkBranch(pluginRun, r.command.branch)
76 if !isAuthorized {
77 continue
78 }
79 r.pluginRun = pluginRun
80 if init := m.ExportedFunction("init"); init != nil {
81 arg, err := pluginRun.Marshal()
82 if err != nil {
83 r.logger.Error("can't marshall pluginRun", err, logger.NewLoggerPair("name", plugin.Name))
84 continue
85 }
86 r.logger.Debug("init plugin worktree", logger.NewLoggerPair("name", plugin.Name), logger.NewLoggerPair("arg", arg))
87 if err := r.writeMemoryAndCall(m, init, malloc, free, repo.Name(), "true", string(arg)); err != nil {
88 r.logger.Error("can't writeMemoryAndCall init", err, logger.NewLoggerPair("name", plugin.Name))
89 continue
90 }
91 }
92
93 if slices.Contains(pluginRun.When, pluginLib.PluginRunWhenAdd) {
94 for _, lastCommit := range commands {
95 firstCall := true
96 hasBeenCalled := false
97 com := commitToCommitForDiff(lastCommit.Commit, []commitForDiffFile{})
98 comMarshalled, err := MarshallOne(r.command.branch.Short(), com)
99 if err != nil {
100 r.logger.Error("can't MarshallOne commit", err, logger.NewLoggerPair("name", plugin.Name))
101 continue
102 }
103 for _, path := range lastCommit.Filepath {
104 if pluginRun.glob.Match(path) {
105 if startCommit != nil && firstCall {
106 firstCall = false
107 if err := r.writeMemoryAndCall(m, startCommit, malloc, free, comMarshalled); err != nil {
108 r.logger.Error("can't writeMemoryAndCall startCommit", err, logger.NewLoggerPair("name", plugin.Name))
109 continue
110 }
111 }
112 if addFile != nil {
113 if err := r.writeMemoryAndCall(m, addFile, malloc, free, strings.TrimPrefix(path, "/")); err != nil {
114 r.logger.Error("can't writeMemoryAndCall addFile", err, logger.NewLoggerPair("name", plugin.Name))
115 continue
116 }
117 hasBeenCalled = true
118 }
119 }
120 }
121 if hasBeenCalled && endCommit != nil {
122 if err := r.writeMemoryAndCall(m, endCommit, malloc, free, comMarshalled); err != nil {
123 r.logger.Error("can't writeMemoryAndCall endCommit", err, logger.NewLoggerPair("name", plugin.Name))
124 continue
125 }
126 }
127 }
128 }
129
130 if finish := m.ExportedFunction("finish"); finish != nil {
131 if _, err := finish.Call(ctx); err != nil {
132 r.logger.Error("can't call finish", err, logger.NewLoggerPair("name", plugin.Name))
133 continue
134 }
135 }
136 }
137
138 l.Debug("memory after worktree", logger.NewLoggerPair("size", m.Memory().Size()), logger.NewLoggerPair("plugin", plugin.Name))
139 r.logger.Debug("finish plugin conf", logger.NewLoggerPair("name", plugin.Name))
140 timerStop()
141 }
142
143 return nil
144}