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("malloc")
 66		free := m.ExportedFunction("free")
 67
 68		for _, pluginRun := range plugin.Run {
 69			isAuthorized := checkBranch(pluginRun, r.command.branch)
 70			if !isAuthorized {
 71				continue
 72			}
 73			r.pluginRun = pluginRun
 74			if init := m.ExportedFunction("init"); init != nil {
 75				arg, err := pluginRun.Marshal()
 76				if err != nil {
 77					r.logger.Error("can't marshall pluginRun", err, logger.NewLoggerPair("name", plugin.Name))
 78					continue
 79				}
 80				r.logger.Debug("init plugin worktree", logger.NewLoggerPair("name", plugin.Name), logger.NewLoggerPair("arg", arg))
 81				if err := writeMemoryAndCall(ctx, m, init, malloc, free, repo.Name(), "true", string(arg)); err != nil {
 82					r.logger.Error("can't writeMemoryAndCall init", err, logger.NewLoggerPair("name", plugin.Name))
 83					continue
 84				}
 85			}
 86
 87			if slices.Contains(pluginRun.When, pluginLib.PluginRunWhenAdd) {
 88				for _, lastCommit := range commands {
 89					firstCall := true
 90					hasBeenCalled := false
 91					com := commitToCommitForDiff(lastCommit.Commit, []commitForDiffFile{})
 92					comMarshalled, err := MarshallOne(r.command.branch.Short(), com)
 93					if err != nil {
 94						r.logger.Error("can't MarshallOne commit", err, logger.NewLoggerPair("name", plugin.Name))
 95						continue
 96					}
 97					for _, path := range lastCommit.Filepath {
 98						if pluginRun.glob.Match(path) {
 99							if startCommit != nil && firstCall {
100								firstCall = false
101								if err := writeMemoryAndCall(ctx, m, startCommit, malloc, free, comMarshalled); err != nil {
102									r.logger.Error("can't writeMemoryAndCall startCommit", err, logger.NewLoggerPair("name", plugin.Name))
103									continue
104								}
105							}
106							if addFile != nil {
107								if err := writeMemoryAndCall(ctx, m, addFile, malloc, free, strings.TrimPrefix(path, "/")); err != nil {
108									r.logger.Error("can't writeMemoryAndCall addFile", err, logger.NewLoggerPair("name", plugin.Name))
109									continue
110								}
111								hasBeenCalled = true
112							}
113						}
114					}
115					if hasBeenCalled && endCommit != nil {
116						if err := writeMemoryAndCall(ctx, m, endCommit, malloc, free, comMarshalled); err != nil {
117							r.logger.Error("can't writeMemoryAndCall endCommit", err, logger.NewLoggerPair("name", plugin.Name))
118							continue
119						}
120					}
121				}
122			}
123
124			if finish := m.ExportedFunction("finish"); finish != nil {
125				if _, err := finish.Call(ctx); err != nil {
126					r.logger.Error("can't call finish", err, logger.NewLoggerPair("name", plugin.Name))
127					continue
128				}
129			}
130		}
131
132		l.Debug("memory after worktree", logger.NewLoggerPair("size", m.Memory().Size()), logger.NewLoggerPair("plugin", plugin.Name))
133		r.logger.Debug("finish plugin conf", logger.NewLoggerPair("name", plugin.Name))
134		timerStop()
135	}
136
137	return nil
138}