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}