// SPDX-FileCopyrightText: 2025 Romain Maneschi // // SPDX-License-Identifier: EUPL-1.2 package plugin import ( "context" "encoding/json" "fmt" "io/fs" "slices" "github.com/go-git/go-git/v6/plumbing" "github.com/samber/oops" pluginLib "gitroot.dev/libs/golang/plugin/model" grfs "gitroot.dev/server/fs" "gitroot.dev/server/logger" "gitroot.dev/server/repository" "gitroot.dev/server/user" ) func (r *runtime) worktree(ctx context.Context, repo *repository.GitRootRepository, repoWriter *repository.GitRootRepositoryWrite, plugins []Plugin, cmds []CommandForDiff) error { r.repo = repo r.repoWriter = repoWriter r.command = &cmds[len(cmds)-1] // TODO should not be last cmd see ./manager.go line 65 todo r.commit = nil filepaths := []string{} fs.WalkDir(repoWriter.ToFs(ctx), ".", func(path string, d fs.DirEntry, err error) error { if !d.IsDir() { filepaths = append(filepaths, path) } return nil }) commands, err := repo.GetLastCommits(filepaths) if err != nil { return err } slices.Reverse(commands) r.commitHook = func(hash plumbing.Hash) { command, err := repoWriter.GetLastCommit(hash) if err != nil { r.logger.Error("can't GetLastCommit", err) return } commands = append(commands, command) } defer func() { r.commitHook = nil }() groups, err := user.LoadGroup(r.repo) if err != nil { return oops.Wrapf(err, "can't load group") } fs := grfs.NewMultiple(ctx, map[string]fs.FS{ "worktree": r.repoWriter.ToFs(ctx), "webcontent": r.manager.conf.DataWeb(r.repo.Name()), }) for _, plugin := range plugins { fs.UpdateSubFs("cache", r.manager.conf.Cache(r.repo.Name(), plugin.Name)) r.plugin = plugin timerStop := r.logger.Time(fmt.Sprintf("Timer %s", plugin.Name)) r.logger.Debug("start plugin worktree", logger.NewLoggerPair("name", plugin.Name)) m, err := r.loadModule(ctx, plugin, fs) if err != nil { r.logger.Error("loadModule for worktree error", err, logger.NewLoggerPair("name", plugin.Name)) continue } l := logger.NewLogger(logger.WASM) l.Debug("memory before worktree", logger.NewLoggerPair("size", m.Memory().Size()), logger.NewLoggerPair("plugin", plugin.Name)) startCommit := m.ExportedFunction("startCommit") endCommit := m.ExportedFunction("endCommit") addFile := m.ExportedFunction("addFile") malloc := m.ExportedFunction("gitrootAlloc") if malloc == nil { malloc = m.ExportedFunction("malloc") } for _, pluginRun := range plugin.Run { isAuthorized := checkBranch(pluginRun, r.command.branch) if !isAuthorized { continue } r.pluginRun = pluginRun if init := m.ExportedFunction("init"); init != nil { arg, err := pluginRun.Marshal() if err != nil { r.logger.Error("can't marshall pluginRun", err, logger.NewLoggerPair("name", plugin.Name)) continue } r.logger.Debug("init plugin worktree", logger.NewLoggerPair("name", plugin.Name), logger.NewLoggerPair("arg", arg)) if err := r.writeMemoryAndCall(m, init, malloc, repo.Name(), "true", string(arg)); err != nil { r.logger.Error("can't writeMemoryAndCall init", err, logger.NewLoggerPair("name", plugin.Name)) continue } } if slices.Contains(pluginRun.When, pluginLib.PluginRunWhenAdd) { for _, lastCommit := range commands { firstCall := true hasBeenCalled := false com := commitToCommitForDiff(lastCommit.Commit, []pluginLib.File{}, groups) r.commit = &com comMarshalled, err := MarshallOne(r.command.branch.Short(), com) if err != nil { r.logger.Error("can't MarshallOne commit", err, logger.NewLoggerPair("name", plugin.Name)) continue } for _, f := range lastCommit.Filepath { if pluginRun.glob.Match(f.Path) { if startCommit != nil && firstCall { firstCall = false if err := r.writeMemoryAndCall(m, startCommit, malloc, comMarshalled); err != nil { r.logger.Error("can't writeMemoryAndCall startCommit", err, logger.NewLoggerPair("name", plugin.Name)) continue } } if addFile != nil { jsonFile, err := json.Marshal(f) if err != nil { r.logger.Error("can marshal file", err, logger.NewLoggerPair("branch", r.command.branch.Short()), logger.NewLoggerPair("plugin", r.plugin.Name)) continue } if err := r.writeMemoryAndCall(m, addFile, malloc, string(jsonFile)); err != nil { r.logger.Error("can't writeMemoryAndCall addFile", err, logger.NewLoggerPair("name", plugin.Name)) continue } hasBeenCalled = true } } } if hasBeenCalled && endCommit != nil { if err := r.writeMemoryAndCall(m, endCommit, malloc, comMarshalled); err != nil { r.logger.Error("can't writeMemoryAndCall endCommit", err, logger.NewLoggerPair("name", plugin.Name)) continue } } } } if finish := m.ExportedFunction("finish"); finish != nil { if _, err := finish.Call(ctx); err != nil { r.logger.Error("can't call finish", err, logger.NewLoggerPair("name", plugin.Name)) continue } } } l.Debug("memory after worktree", logger.NewLoggerPair("size", m.Memory().Size()), logger.NewLoggerPair("plugin", plugin.Name)) r.logger.Debug("finish plugin conf", logger.NewLoggerPair("name", plugin.Name)) timerStop() } return nil }