mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-17 20:41:49 +03:00
90 lines
2.5 KiB
Go
90 lines
2.5 KiB
Go
|
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 (
|
||
|
"io/ioutil"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/ghodss/yaml"
|
||
|
"github.com/hasura/graphql-engine/cli/plugins/paths"
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
func (c *Config) findPluginManifestFiles(indexDir string) ([]string, error) {
|
||
|
var out []string
|
||
|
files, err := ioutil.ReadDir(indexDir)
|
||
|
if err != nil {
|
||
|
return nil, errors.Wrap(err, "failed to open index dir")
|
||
|
}
|
||
|
for _, file := range files {
|
||
|
if file.Mode().IsRegular() && filepath.Ext(file.Name()) == paths.ManifestExtension {
|
||
|
out = append(out, file.Name())
|
||
|
}
|
||
|
}
|
||
|
return out, nil
|
||
|
}
|
||
|
|
||
|
// LoadPluginListFromFS will parse and retrieve all plugin files.
|
||
|
func (c *Config) LoadPluginListFromFS(indexDir string) ([]Plugin, error) {
|
||
|
indexDir, err := filepath.EvalSymlinks(indexDir)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
files, err := c.findPluginManifestFiles(indexDir)
|
||
|
if err != nil {
|
||
|
return nil, errors.Wrap(err, "failed to scan plugins in index directory")
|
||
|
}
|
||
|
|
||
|
list := make([]Plugin, 0, len(files))
|
||
|
for _, file := range files {
|
||
|
pluginName := strings.TrimSuffix(file, filepath.Ext(file))
|
||
|
p, err := c.LoadPluginByName(indexDir, pluginName)
|
||
|
if err != nil {
|
||
|
continue
|
||
|
}
|
||
|
list = append(list, p)
|
||
|
}
|
||
|
return list, nil
|
||
|
}
|
||
|
|
||
|
// LoadPluginByName loads a plugins index file by its name. When plugin
|
||
|
// file not found, it returns an error that can be checked with os.IsNotExist.
|
||
|
func (c *Config) LoadPluginByName(pluginsDir, pluginName string) (Plugin, error) {
|
||
|
if !IsSafePluginName(pluginName) {
|
||
|
return Plugin{}, errors.Errorf("plugin name %q not allowed", pluginName)
|
||
|
}
|
||
|
|
||
|
return c.ReadPluginFromFile(filepath.Join(pluginsDir, pluginName+paths.ManifestExtension))
|
||
|
}
|
||
|
|
||
|
// ReadPluginFromFile loads a file from the FS. When plugin file not found, it
|
||
|
// returns an error that can be checked with os.IsNotExist.
|
||
|
func (c *Config) ReadPluginFromFile(path string) (Plugin, error) {
|
||
|
f, err := os.Open(path)
|
||
|
if os.IsNotExist(err) {
|
||
|
return Plugin{}, err
|
||
|
} else if err != nil {
|
||
|
return Plugin{}, errors.Wrap(err, "failed to open index file")
|
||
|
}
|
||
|
defer f.Close()
|
||
|
var plugin Plugin
|
||
|
b, err := ioutil.ReadAll(f)
|
||
|
if err != nil {
|
||
|
return plugin, err
|
||
|
}
|
||
|
err = yaml.Unmarshal(b, &plugin)
|
||
|
if err != nil {
|
||
|
return plugin, errors.Wrap(err, "failed to decode plugin manifest")
|
||
|
}
|
||
|
return plugin, errors.Wrap(plugin.ValidatePlugin(plugin.Name), "plugin manifest validation error")
|
||
|
}
|