-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathplugin.go
110 lines (92 loc) · 3.49 KB
/
plugin.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package filepaths
import (
"fmt"
"log/slog"
"os"
"path/filepath"
"github.com/turbot/pipe-fittings/v2/constants"
"github.com/turbot/pipe-fittings/v2/error_helpers"
"github.com/turbot/pipe-fittings/v2/utils"
)
const (
localPluginFolder = "local"
)
// EnsurePluginDir returns the path to the plugins directory (creates if missing)
func EnsurePluginDir() string {
return ensureInstallSubDir("plugins")
}
func EnsurePluginInstallDir(pluginImageDisplayRef string) string {
installDir := PluginInstallDir(pluginImageDisplayRef)
if _, err := os.Stat(installDir); os.IsNotExist(err) {
err = os.MkdirAll(installDir, 0755)
error_helpers.FailOnErrorWithMessage(err, "could not create plugin install directory")
}
return installDir
}
func PluginInstallDir(pluginImageDisplayRef string) string {
osSafePath := filepath.FromSlash(pluginImageDisplayRef)
fullPath := filepath.Join(EnsurePluginDir(), osSafePath)
return fullPath
}
func PluginBinaryPath(pluginImageDisplayRef, pluginAlias string) string {
return filepath.Join(PluginInstallDir(pluginImageDisplayRef), PluginAliasToLongName(pluginAlias)+".plugin")
}
func GetPluginPath(pluginImageRef, pluginAlias string) (string, error) {
// the fully qualified name of the plugin is the relative path of the folder containing the plugin
// calculate absolute folder path
pluginFolder := filepath.Join(EnsurePluginDir(), pluginImageRef)
// 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) {
slog.Debug("plugin path not found - searching for folder using hashed name", "plugin path", pluginFolder)
if pluginFolder, err = FindPluginFolder(pluginImageRef); err != nil {
return "", err
} else if pluginFolder == "" {
return "", fmt.Errorf("no plugin installed matching '%s'", pluginAlias)
}
}
// 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", pluginImageRef, err)
}
var 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
}
// FindPluginFolder searches for a folder which when hashed would match the schema
func FindPluginFolder(remoteSchema string) (string, error) {
pluginDir := EnsurePluginDir()
// first try searching by prefix - trim the schema name
globPattern := filepath.Join(pluginDir, utils.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 match from the plugin folder
folderRelativePath, err := filepath.Rel(pluginDir, match)
if err != nil {
// do not fail on error here
continue
}
hashedName := utils.PluginFQNToSchemaName(folderRelativePath)
if hashedName == remoteSchema {
return filepath.Join(pluginDir, folderRelativePath), nil
}
}
return "", nil
}
// LocalPluginPath returns the path to locally installed plugins
func LocalPluginPath() string {
return filepath.Join(EnsurePluginDir(), localPluginFolder)
}