2020-02-24 19:14:46 +03:00
|
|
|
package plugins
|
|
|
|
|
|
|
|
/*
|
|
|
|
some of the code here is borrowed from the krew codebse (kubernetes)
|
|
|
|
and the copyright belongs to the respective authors.
|
|
|
|
|
|
|
|
source: https://github.com/kubernetes-sigs/krew/tree/master/internal
|
|
|
|
*/
|
|
|
|
|
|
|
|
import (
|
2022-11-10 09:42:13 +03:00
|
|
|
stderrors "errors"
|
2020-02-24 19:14:46 +03:00
|
|
|
"fmt"
|
2022-11-10 09:42:13 +03:00
|
|
|
"io/fs"
|
2020-02-24 19:14:46 +03:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"runtime"
|
|
|
|
|
|
|
|
"github.com/Masterminds/semver"
|
2020-04-07 17:12:14 +03:00
|
|
|
|
2021-05-14 22:09:01 +03:00
|
|
|
"github.com/goccy/go-yaml"
|
2022-11-02 14:10:41 +03:00
|
|
|
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
|
2021-06-16 14:44:15 +03:00
|
|
|
"github.com/hasura/graphql-engine/cli/v2/plugins/paths"
|
|
|
|
"github.com/hasura/graphql-engine/cli/v2/util"
|
2020-02-24 19:14:46 +03:00
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2022-11-02 14:10:41 +03:00
|
|
|
ErrIsAlreadyInstalled = fmt.Errorf("can't install, plugin is already installed")
|
|
|
|
ErrIsNotInstalled = fmt.Errorf("plugin is not installed")
|
|
|
|
ErrIsAlreadyUpgraded = fmt.Errorf("can't upgrade, the newest version is already installed")
|
|
|
|
ErrVersionNotAvailable = fmt.Errorf("plugin version is not available")
|
2020-02-24 19:14:46 +03:00
|
|
|
)
|
|
|
|
|
2020-04-16 04:24:50 +03:00
|
|
|
// IndexBranchRef - branch to be used for index
|
|
|
|
var IndexBranchRef = "master"
|
|
|
|
|
2020-02-24 19:14:46 +03:00
|
|
|
const (
|
|
|
|
indexURI string = "https://github.com/hasura/cli-plugins-index.git"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Config defines the required
|
|
|
|
type Config struct {
|
|
|
|
// Paths contains all important environment paths
|
|
|
|
Paths paths.Paths
|
|
|
|
|
|
|
|
// Repo defines the git object required to maintain the plugin index
|
|
|
|
Repo *util.GitUtil
|
|
|
|
|
|
|
|
Logger *logrus.Logger
|
|
|
|
}
|
|
|
|
|
2020-04-22 12:15:42 +03:00
|
|
|
// FetchOpts - options available during fetching plugin manifest
|
|
|
|
type FetchOpts struct {
|
2020-04-13 06:16:06 +03:00
|
|
|
ManifestFile string
|
|
|
|
|
|
|
|
Version *semver.Version
|
|
|
|
}
|
|
|
|
|
2020-02-24 19:14:46 +03:00
|
|
|
func New(base string) *Config {
|
|
|
|
p := paths.NewPaths(base)
|
|
|
|
return &Config{
|
|
|
|
Paths: p,
|
2020-04-16 04:24:50 +03:00
|
|
|
Repo: util.NewGitUtil(indexURI, p.IndexPath(), IndexBranchRef),
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare makes sure that the plugins directory is initialized
|
|
|
|
func (c *Config) Prepare() error {
|
2022-11-02 14:10:41 +03:00
|
|
|
var op errors.Op = "plugins.Config.Prepare"
|
|
|
|
err := ensureDirs(c.Paths.BasePath(),
|
2020-02-24 19:14:46 +03:00
|
|
|
c.Paths.DownloadPath(),
|
|
|
|
c.Paths.InstallPath(),
|
|
|
|
c.Paths.BinPath(),
|
|
|
|
c.Paths.InstallReceiptsPath(),
|
2022-11-02 14:10:41 +03:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return errors.E(op, fmt.Errorf("unable to create plugin directories: %w", err))
|
|
|
|
}
|
|
|
|
return nil
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// ListInstalledPlugins returns a list of all install plugins in a
|
|
|
|
// name:version format based on the install receipts at the specified dir.
|
|
|
|
func (c *Config) ListInstalledPlugins() (map[string]string, error) {
|
2022-11-02 14:10:41 +03:00
|
|
|
var op errors.Op = "plugins.Config.ListInstalledPlugins"
|
2020-02-24 19:14:46 +03:00
|
|
|
receiptsDir := c.Paths.InstallReceiptsPath()
|
|
|
|
matches, err := filepath.Glob(filepath.Join(receiptsDir, "*"+paths.ManifestExtension))
|
|
|
|
if err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return nil, errors.E(op, fmt.Errorf("failed to grab receipts directory (%s) for manifests: %w", receiptsDir, err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
installed := make(map[string]string)
|
|
|
|
for _, m := range matches {
|
|
|
|
r, err := c.LoadManifest(m)
|
|
|
|
if err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return nil, errors.E(op, fmt.Errorf("failed to parse plugin install receipt %s: %w", m, err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
installed[r.Name] = r.Version
|
|
|
|
}
|
|
|
|
return installed, nil
|
|
|
|
}
|
|
|
|
|
2020-04-07 17:12:14 +03:00
|
|
|
func (c *Config) ListPlugins() (Plugins, error) {
|
2022-11-02 14:10:41 +03:00
|
|
|
var op errors.Op = "plugins.Config.ListPlugins"
|
|
|
|
plugins, err := c.LoadPluginListFromFS(c.Paths.IndexPluginsPath())
|
|
|
|
if err != nil {
|
|
|
|
return plugins, errors.E(op, err)
|
|
|
|
}
|
|
|
|
return plugins, nil
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
2020-04-22 12:15:42 +03:00
|
|
|
func (c *Config) GetPlugin(pluginName string, opts FetchOpts) (Plugin, error) {
|
2022-11-02 14:10:41 +03:00
|
|
|
var op errors.Op = "plugins.Config.GetPlugin"
|
2020-02-24 19:14:46 +03:00
|
|
|
var plugin Plugin
|
|
|
|
var err error
|
2020-04-13 06:16:06 +03:00
|
|
|
if opts.ManifestFile == "" {
|
2020-02-24 19:14:46 +03:00
|
|
|
// Load the plugin index by name
|
2020-04-07 17:12:14 +03:00
|
|
|
ps, err := c.LoadPluginByName(pluginName)
|
2020-02-24 19:14:46 +03:00
|
|
|
if err != nil {
|
2022-11-10 09:42:13 +03:00
|
|
|
if stderrors.Is(err, fs.ErrNotExist) {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, fmt.Errorf("plugin %q does not exist in the plugin index", pluginName))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, fmt.Errorf("failed to load plugin %q from the index: %w", pluginName, err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Load the installed manifest
|
2020-04-07 17:12:14 +03:00
|
|
|
pluginReceipt, err := c.LoadManifest(c.Paths.PluginInstallReceiptPath(pluginName))
|
2022-11-10 09:42:13 +03:00
|
|
|
if err != nil && !stderrors.Is(err, fs.ErrNotExist) {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, fmt.Errorf("failed to look up plugin receipt: %w", err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
2020-04-07 17:12:14 +03:00
|
|
|
|
2020-04-13 06:16:06 +03:00
|
|
|
if opts.Version != nil {
|
|
|
|
if pluginReceipt.Version == opts.Version.Original() {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, ErrIsAlreadyInstalled)
|
2020-04-07 17:12:14 +03:00
|
|
|
}
|
|
|
|
// check if version is available
|
2020-04-13 06:16:06 +03:00
|
|
|
ver := ps.Index.Search(opts.Version)
|
2020-04-07 17:12:14 +03:00
|
|
|
if ver != nil {
|
|
|
|
plugin = ps.Versions[ver]
|
|
|
|
} else {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, ErrVersionNotAvailable)
|
2020-04-07 17:12:14 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if err == nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, ErrIsAlreadyInstalled)
|
2020-04-07 17:12:14 +03:00
|
|
|
}
|
|
|
|
// get the latest version
|
|
|
|
latestVersion := ps.Index[len(ps.Index)-1]
|
|
|
|
plugin = ps.Versions[latestVersion]
|
|
|
|
}
|
2020-02-24 19:14:46 +03:00
|
|
|
} else {
|
2020-04-13 06:16:06 +03:00
|
|
|
plugin, err = c.ReadPluginFromFile(opts.ManifestFile)
|
2020-02-24 19:14:46 +03:00
|
|
|
if err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, fmt.Errorf("failed to load plugin manifest from file: %w", err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
if plugin.Name != pluginName {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, fmt.Errorf("plugin name %s doesn't match with plugin in the manifest file %s", pluginName, opts.ManifestFile))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
}
|
2020-04-22 12:15:42 +03:00
|
|
|
return plugin, nil
|
|
|
|
}
|
2020-02-24 19:14:46 +03:00
|
|
|
|
2020-04-22 12:15:42 +03:00
|
|
|
func (c *Config) Install(plugin Plugin) error {
|
2022-11-02 14:10:41 +03:00
|
|
|
var op errors.Op = "plugins.Config.Install"
|
2020-02-24 19:14:46 +03:00
|
|
|
// Find available installation platform
|
|
|
|
platform, ok, err := MatchPlatform(plugin.Platforms)
|
|
|
|
if err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("failed trying to find a matching platform in plugin spec: %w", err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
if !ok {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("plugin %q does not offer installation for this platform", plugin.Name))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
if err := c.installPlugin(plugin, platform); err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("install failed: %w", err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
err = c.StoreManifest(plugin, c.Paths.PluginInstallReceiptPath(plugin.Name))
|
2022-11-02 14:10:41 +03:00
|
|
|
if err != nil {
|
|
|
|
return errors.E(op, fmt.Errorf("installation receipt could not be stored, uninstall may fail: %w", err))
|
|
|
|
}
|
|
|
|
return nil
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Uninstall will uninstall a plugin.
|
|
|
|
func (c *Config) Uninstall(name string) error {
|
2022-11-02 14:10:41 +03:00
|
|
|
var op errors.Op = "plugins.Config.Uninstall"
|
2020-02-24 19:14:46 +03:00
|
|
|
if _, err := c.LoadManifest(c.Paths.PluginInstallReceiptPath(name)); err != nil {
|
2022-11-10 09:42:13 +03:00
|
|
|
if stderrors.Is(err, fs.ErrNotExist) {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, ErrIsNotInstalled)
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("failed to look up install receipt for plugin %q: %w", name, err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
2020-04-13 06:16:06 +03:00
|
|
|
symlinkPath := filepath.Join(c.Paths.BinPath(), PluginNameToBin(name, IsWindows()))
|
2020-02-24 19:14:46 +03:00
|
|
|
if err := removeLink(symlinkPath); err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("could not uninstall symlink of plugin: %w", err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pluginInstallPath := c.Paths.PluginInstallPath(name)
|
|
|
|
if err := os.RemoveAll(pluginInstallPath); err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("could not remove plugin directory %q: %w", pluginInstallPath, err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
pluginReceiptPath := c.Paths.PluginInstallReceiptPath(name)
|
|
|
|
err := os.Remove(pluginReceiptPath)
|
2022-11-02 14:10:41 +03:00
|
|
|
if err != nil {
|
|
|
|
return errors.E(op, fmt.Errorf("could not remove plugin receipt %q: %w", pluginReceiptPath, err))
|
|
|
|
}
|
|
|
|
return nil
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) installPlugin(plugin Plugin, platform Platform) error {
|
2022-11-02 14:10:41 +03:00
|
|
|
var op errors.Op = "plugins.Config.installPlugin"
|
2020-02-24 19:14:46 +03:00
|
|
|
downloadStagingDir := filepath.Join(c.Paths.DownloadPath(), plugin.Name)
|
|
|
|
installDir := c.Paths.PluginVersionInstallPath(plugin.Name, plugin.Version)
|
|
|
|
binDir := c.Paths.BinPath()
|
|
|
|
|
2020-04-07 17:12:14 +03:00
|
|
|
// check if install dir already exists
|
|
|
|
_, err := os.Stat(installDir)
|
|
|
|
if err != nil {
|
|
|
|
// Download and extract
|
|
|
|
if err := os.MkdirAll(downloadStagingDir, 0755); err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("could not create staging dir %q: %w", downloadStagingDir, err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
2020-04-07 17:12:14 +03:00
|
|
|
defer func() {
|
|
|
|
c.Logger.Debugf("Deleting the download staging directory %s", downloadStagingDir)
|
|
|
|
if err := os.RemoveAll(downloadStagingDir); err != nil {
|
|
|
|
c.Logger.Debugf("failed to clean up download staging directory: %s", err)
|
|
|
|
}
|
|
|
|
}()
|
2020-02-24 19:14:46 +03:00
|
|
|
|
2020-04-07 17:12:14 +03:00
|
|
|
if err := downloadAndExtract(downloadStagingDir, platform.URI, platform.Sha256); err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("failed to unpack into staging dir: %w", err))
|
2020-04-07 17:12:14 +03:00
|
|
|
}
|
2020-02-24 19:14:46 +03:00
|
|
|
|
2020-04-07 17:12:14 +03:00
|
|
|
if err := moveToInstallDir(downloadStagingDir, installDir, platform.Files); err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("failed while moving files to the installation directory: %w", err))
|
2020-04-07 17:12:14 +03:00
|
|
|
}
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
subPathAbs, err := filepath.Abs(installDir)
|
|
|
|
if err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("failed to get the absolute fullPath of %q: %w", installDir, err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
fullPath := filepath.Join(installDir, filepath.FromSlash(platform.Bin))
|
|
|
|
pathAbs, err := filepath.Abs(fullPath)
|
|
|
|
if err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("failed to get the absolute fullPath of %q: %w", fullPath, err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
if _, ok := IsSubPath(subPathAbs, pathAbs); !ok {
|
2022-11-02 14:10:41 +03:00
|
|
|
if err != nil {
|
|
|
|
return errors.E(op, fmt.Errorf("the fullPath %q does not extend the sub-fullPath %q: %w", fullPath, installDir, err))
|
|
|
|
}
|
|
|
|
return nil
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
err = createOrUpdateLink(binDir, fullPath, plugin.Name)
|
2022-11-02 14:10:41 +03:00
|
|
|
if err != nil {
|
|
|
|
return errors.E(op, fmt.Errorf("failed to link installed plugin: %w", err))
|
|
|
|
}
|
|
|
|
return nil
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Upgrade will reinstall and delete the old plugin. The operation tries
|
|
|
|
// to not get the plugin dir in a bad state if it fails during the process.
|
2020-04-07 17:12:14 +03:00
|
|
|
func (c *Config) Upgrade(pluginName string, version *semver.Version) (Plugin, error) {
|
2022-11-02 14:10:41 +03:00
|
|
|
var op errors.Op = "plugins.Config.Upgrade"
|
2020-04-07 17:12:14 +03:00
|
|
|
ps, err := c.LoadPluginByName(pluginName)
|
2020-02-24 19:14:46 +03:00
|
|
|
if err != nil {
|
2022-11-10 09:42:13 +03:00
|
|
|
if stderrors.Is(err, fs.ErrNotExist) {
|
2022-11-02 14:10:41 +03:00
|
|
|
return Plugin{}, errors.E(op, fmt.Errorf("plugin %q does not exist in the plugin index", pluginName))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
2022-11-02 14:10:41 +03:00
|
|
|
return Plugin{}, errors.E(op, fmt.Errorf("failed to load the plugin manifest for plugin %s: %w", pluginName, err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
2020-04-07 17:12:14 +03:00
|
|
|
|
|
|
|
// get the latest version
|
|
|
|
var plugin Plugin
|
|
|
|
if version != nil {
|
|
|
|
ver := ps.Index.Search(version)
|
|
|
|
if ver != nil {
|
|
|
|
plugin = ps.Versions[ver]
|
|
|
|
} else {
|
2022-11-02 14:10:41 +03:00
|
|
|
return Plugin{}, errors.E(op, ErrVersionNotAvailable)
|
2020-04-07 17:12:14 +03:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
latestVersion := ps.Index[len(ps.Index)-1]
|
|
|
|
plugin = ps.Versions[latestVersion]
|
|
|
|
}
|
|
|
|
|
2020-02-24 19:14:46 +03:00
|
|
|
installReceipt, err := c.LoadManifest(c.Paths.PluginInstallReceiptPath(plugin.Name))
|
|
|
|
if err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, fmt.Errorf("failed to load install receipt for plugin %q: %w", plugin.Name, err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
2020-04-07 17:12:14 +03:00
|
|
|
if installReceipt.ParsedVersion == nil {
|
|
|
|
c.Logger.Debugf("failed to parse installed plugin version (%q) as a semver value", installReceipt.ParsedVersion)
|
2020-02-24 19:14:46 +03:00
|
|
|
c.Logger.Debugf("assuming installed plugin %s as a dev version and force upgrade", plugin.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find available installation platform
|
|
|
|
platform, ok, err := MatchPlatform(plugin.Platforms)
|
|
|
|
if err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, fmt.Errorf("failed trying to find a matching platform in plugin spec: %w", err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
if !ok {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, fmt.Errorf("plugin %q does not offer installation for this platform (%s)",
|
|
|
|
plugin.Name, fmt.Sprintf("%s-%s", runtime.GOOS, runtime.GOARCH)))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// See if it's a newer version
|
2020-04-07 17:12:14 +03:00
|
|
|
if installReceipt.ParsedVersion != nil {
|
|
|
|
if !installReceipt.ParsedVersion.LessThan(plugin.ParsedVersion) || installReceipt.ParsedVersion.Equal(plugin.ParsedVersion) {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, ErrIsAlreadyUpgraded)
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = c.StoreManifest(plugin, c.Paths.PluginInstallReceiptPath(plugin.Name)); err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, fmt.Errorf("installation receipt could not be stored, uninstall may fail: %w", err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Re-Install
|
|
|
|
if err := c.installPlugin(plugin, platform); err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return plugin, errors.E(op, fmt.Errorf("failed to install new version: %w", err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Clean old installations
|
2022-11-02 14:10:41 +03:00
|
|
|
err = os.RemoveAll(c.Paths.PluginVersionInstallPath(plugin.Name, installReceipt.Version))
|
|
|
|
if err != nil {
|
|
|
|
return plugin, errors.E(op, err)
|
|
|
|
}
|
|
|
|
return plugin, nil
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) LoadManifest(path string) (Plugin, error) {
|
2022-11-02 14:10:41 +03:00
|
|
|
var op errors.Op = "plugins.Config.LoadManifest"
|
|
|
|
plugin, err := c.ReadPluginFromFile(path)
|
|
|
|
if err != nil {
|
|
|
|
return plugin, errors.E(op, err)
|
|
|
|
}
|
|
|
|
return plugin, nil
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) StoreManifest(plugin Plugin, dest string) error {
|
2022-11-02 14:10:41 +03:00
|
|
|
var op errors.Op = "plugins.Config.StoreManifest"
|
2020-02-24 19:14:46 +03:00
|
|
|
yamlBytes, err := yaml.Marshal(plugin)
|
|
|
|
if err != nil {
|
2022-11-02 14:10:41 +03:00
|
|
|
return errors.E(op, fmt.Errorf("convert to yaml: %w", err))
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|
|
|
|
err = ioutil.WriteFile(dest, yamlBytes, 0644)
|
2022-11-02 14:10:41 +03:00
|
|
|
if err != nil {
|
|
|
|
return errors.E(op, fmt.Errorf("write plugin receipt %q: %w", dest, err))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
|
2020-02-24 19:14:46 +03:00
|
|
|
}
|