mirror of
https://github.com/turbot/steampipe.git
synced 2025-12-26 15:00:08 -05:00
General code spring cleaning: * move file paths from `consts` package to `filepaths` * move InitData and ExportData to query and control packages
100 lines
3.1 KiB
Go
100 lines
3.1 KiB
Go
package pluginmanager
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/turbot/steampipe/constants"
|
|
"github.com/turbot/steampipe/filepaths"
|
|
"github.com/turbot/steampipe/utils"
|
|
)
|
|
|
|
const maxSchemaNameLength = 63
|
|
|
|
func GetPluginPath(plugin, pluginShortName string) (string, error) {
|
|
remoteSchema := plugin
|
|
// the fully qualified name of the plugin is the relative path of the folder containing the plugin
|
|
// calculate absolute folder path
|
|
pluginFolder := filepath.Join(filepaths.PluginDir(), remoteSchema)
|
|
|
|
// if the plugin folder is missing, it is possible the plugin path was truncated to create a schema name
|
|
// - so search for a folder which when truncated would match the schema
|
|
if _, err := os.Stat(pluginFolder); os.IsNotExist(err) {
|
|
log.Printf("[TRACE] plugin path %s not found - searching for folder using hashed name\n", pluginFolder)
|
|
if pluginFolder, err = FindPluginFolder(remoteSchema); err != nil {
|
|
return "", err
|
|
} else if pluginFolder == "" {
|
|
return "", fmt.Errorf("no plugin installed matching %s", pluginShortName)
|
|
}
|
|
}
|
|
|
|
// there should be just 1 file with extension pluginExtension (".plugin")
|
|
entries, err := os.ReadDir(pluginFolder)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to load plugin %s: %v", remoteSchema, err)
|
|
}
|
|
matches := []string{}
|
|
for _, entry := range entries {
|
|
if filepath.Ext(entry.Name()) == constants.PluginExtension {
|
|
matches = append(matches, entry.Name())
|
|
}
|
|
}
|
|
if len(matches) != 1 {
|
|
return "", fmt.Errorf("plugin folder %s should contain a single plugin file. %d plugins were found ", pluginFolder, len(matches))
|
|
}
|
|
|
|
return filepath.Join(pluginFolder, matches[0]), nil
|
|
}
|
|
|
|
// PluginFQNToSchemaName convert a full plugin name to a schema name
|
|
// schemas in postgres are limited to 63 chars - the name may be longer than this, in which case trim the length
|
|
// and add a hash to the end to make unique
|
|
func PluginFQNToSchemaName(pluginFQN string) string {
|
|
if len(pluginFQN) < maxSchemaNameLength {
|
|
return pluginFQN
|
|
}
|
|
|
|
schemaName := trimSchemaName(pluginFQN) + fmt.Sprintf("-%x", utils.StringHash(pluginFQN))
|
|
return schemaName
|
|
}
|
|
|
|
func trimSchemaName(pluginFQN string) string {
|
|
if len(pluginFQN) < maxSchemaNameLength {
|
|
return pluginFQN
|
|
}
|
|
|
|
return pluginFQN[:maxSchemaNameLength-9]
|
|
}
|
|
|
|
// FindPluginFolder searches for a folder which when hashed would match the schema
|
|
func FindPluginFolder(remoteSchema string) (string, error) {
|
|
pluginDir := filepaths.PluginDir()
|
|
|
|
// first try searching by prefix - trim the schema name
|
|
globPattern := filepath.Join(pluginDir, trimSchemaName(remoteSchema)) + "*"
|
|
matches, err := filepath.Glob(globPattern)
|
|
if err != nil {
|
|
return "", err
|
|
} else if len(matches) == 1 {
|
|
return matches[0], nil
|
|
}
|
|
|
|
for _, match := range matches {
|
|
// // get the relative path to this mat fromn the plugin folder
|
|
folderRelativePath, err := filepath.Rel(pluginDir, match)
|
|
if err != nil {
|
|
// do not fail on error here
|
|
continue
|
|
}
|
|
hashedName := PluginFQNToSchemaName(folderRelativePath)
|
|
if hashedName == remoteSchema {
|
|
log.Printf("[TRACE] folder %s matches %s\n", folderRelativePath, remoteSchema)
|
|
return filepath.Join(pluginDir, folderRelativePath), nil
|
|
}
|
|
}
|
|
|
|
return "", nil
|
|
}
|