// SPDX-FileCopyrightText: 2025 Romain Maneschi // // SPDX-License-Identifier: EUPL-1.2 package plugin import ( "context" "errors" "os" "sync" "github.com/go-git/go-git/v5/plumbing/object" "github.com/samber/oops" "gitroot.dev/server/logger" ) func (pm *Manager) reloadPlugins() { pm.pluginsLock.Lock() pm.plugins = nil pm.pluginsLock.Unlock() pm.Availables(context.Background()) //TODO pass good context } func (pm *Manager) Availables(ctx context.Context) ([]Plugin, error) { pm.pluginsLock.Lock() defer pm.pluginsLock.Unlock() needLoad := pm.plugins == nil if needLoad { pm.logger.Info("availables needLoad") errorHandler := oops.With("rootData", pm.conf.PathDataPlugin()) forgeRepo, err := pm.repoManager.OpenForgeRepo(logger.AddCaller(ctx, "plugin.Availables")) defer func() { if err := forgeRepo.Close(); err != nil { pm.logger.Error("forgeRepo.Close", err) } }() if err != nil { return nil, errorHandler.Wrapf(err, "can't open forgeRepo") } filecontent, err := forgeRepo.ContentPluginsConf() if errors.Is(err, object.ErrFileNotFound) { return []Plugin{}, nil } else if err != nil { return nil, oops.Wrapf(err, "can't read plugins filecontent from repo") } ps, err := ParsePlugins(filecontent, false) if err != nil { return nil, oops.Wrapf(err, "can't parse plugins from repo") } pm.plugins = make([]Plugin, 0) timeLoading := pm.logger.Time("loading wasm files", logger.NewLoggerPairNamedSlice("plugins", ps)) wg := sync.WaitGroup{} for i, cp := range ps { wg.Add(1) go func(i int, cp Plugin) { defer wg.Done() content, err := os.ReadFile(pm.PathWasm(cp)) if err != nil { pm.logger.Error("can't read plugin", err, logger.NewLoggerPair("filename", cp.Name), logger.NewLoggerPair("path", pm.PathWasm(cp))) return } compiled, err := pm.runtimes.Compile(ctx, content) if err != nil { pm.logger.Error("can't compile plugin", err, logger.NewLoggerPair("filename", cp.Name), logger.NewLoggerPair("path", pm.PathWasm(cp))) return } if cp.Name == "" { cp = cp.DetermineNameAndVersionFromUrl() } if len(cp.Run) == 0 { conf, err := pm.runtimes.Conf(ctx, Plugin{Name: cp.Name, Version: cp.Version, compiledModule: compiled}) if err != nil { pm.logger.Error("can't get default conf", err, logger.NewLoggerPair("filename", cp.Name)) return } run, err := pluginLibToPlugin(conf.DefaultRun) if err != nil { pm.logger.Error("can't pluginLibToPlugin", err, logger.NewLoggerPair("filename", cp.Name)) return } else { cp.Run = run } if conf.SdkVersion != "0.4.0" { pm.logger.Error("bad sdk version need update", err, logger.NewLoggerPair("plugin", cp.Name), logger.NewLoggerPair("sdkVersion", conf.SdkVersion)) return } } commiter, err := pm.userManager.NewCommiter(cp.Name) if err != nil { pm.logger.Error("NewCommiter", err, logger.NewLoggerPair("pluginName", cp.Name)) } pm.plugins = append(pm.plugins, Plugin{ Url: cp.Url, Checksum: cp.Checksum, Active: cp.Active, Name: cp.Name, Version: cp.Version, Run: cp.Run, compiledModule: compiled, commiter: commiter, }) pm.logger.Info("available plugin", logger.NewLoggerPair("name", cp.Name)) }(i, cp) } wg.Wait() timeLoading() } if len(pm.plugins) == 0 { pm.logger.Info("no available plugin", logger.NewLoggerPair("in dir", pm.conf.PathDataPlugin())) } return pm.plugins, nil } func (pm *Manager) usableFromDefaultBranch(ctx context.Context, repoName string) ([]Plugin, error) { pm.logger.Debug("usableFromDefaultBranch before open", logger.NewLoggerPair("repoName", repoName)) repo, err := pm.repoManager.Open(logger.AddCaller(ctx, "plugin.usable"), repoName) if err != nil { return nil, oops.Wrapf(err, "can't open repo") } defer repo.Close() pm.logger.Debug("usableFromDefaultBranch before ContentPluginsConf", logger.NewLoggerPair("repoName", repoName)) filecontent, err := repo.ContentPluginsConf() if err != nil { return nil, oops.Wrapf(err, "can't read plugins from repo") } confPlugins, err := ParsePlugins(filecontent, true) if err != nil { return nil, oops.Wrapf(err, "can't parse plugins from repo") } if len(confPlugins) == 0 { pm.logger.Debug("no usable plugin in conf") } pm.logger.Debug("usableFromDefaultBranch before Availables", logger.NewLoggerPair("repoName", repoName)) plugins, err := pm.Availables(ctx) if err != nil { return nil, oops.Wrapf(err, "can't get availables plugin from forgerepo") } pm.logger.Debug("availables plugins", logger.NewLoggerPairNamedSlice("names", plugins)) pm.logger.Debug("project plugins", logger.NewLoggerPairNamedSlice("names", confPlugins)) usablePlugins := make([]Plugin, 0) for _, cp := range confPlugins { for _, p := range plugins { if p.Name == cp.Name { if cp.Active { goodP := p.OverrideWith(cp).SetActive(cp.Active).SetRun(cp.Run) usablePlugins = append(usablePlugins, goodP) pm.logger.Debug("usable plugin", logger.NewLoggerPair("name", cp.Name)) } break } } } return usablePlugins, nil }