This repository has been archived by the owner on Jan 14, 2020. It is now read-only.
/
load.go
193 lines (168 loc) · 5.22 KB
/
load.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package plugins
import (
"fmt"
"os"
"plugin"
printer "github.com/KablamoOSS/go-cli-printer"
"github.com/KablamoOSS/kombustion/internal/manifest"
"github.com/KablamoOSS/kombustion/internal/plugins/lock"
pluginTypes "github.com/KablamoOSS/kombustion/pkg/plugins/api/types"
)
// LoadPlugins from a manifest and lockfile
func LoadPlugins(manifestFile *manifest.Manifest, lockFile *lock.Lock) (loadedPlugins []*PluginLoaded) {
// Load all plugins the manifest
for _, manifestPlugin := range manifestFile.Plugins {
for _, plugin := range lockFile.Plugins {
// Find the matching plugin in the lock file
if plugin.Match(&manifestPlugin) {
resolution := plugin.ResolveForRuntime()
if resolution == nil {
printer.Fatal(
fmt.Errorf("Could not resolve plugin %s", plugin.Name),
"Ensure plugin supports your operating system and architecture",
"",
)
}
loadedPlugins = append(
loadedPlugins,
loadPlugin(plugin.Name, plugin.Version, resolution.PathOnDisk, resolution.Hash, false, manifestPlugin.Alias),
)
} else {
printer.Fatal(
fmt.Errorf("Plugin `%s@%s` is not installed, but is included in kombustion.yaml", manifestPlugin.Name, manifestPlugin.Version),
"Run `kombustion install`",
"",
)
}
}
}
return
}
// LoadDevPlugin loads an arbitrary plugin for plugin developers, to ease plugin development.
// Only works with a kombustion binary that was built from source
func LoadDevPlugin(pluginPath string) *PluginLoaded {
return loadPlugin(
"dev-loaded-plugin",
"DEV",
pluginPath,
"",
true,
"",
)
}
func loadPlugin(
name string,
version string,
path string,
expectedHash string,
isDevPlugin bool,
alias string,
) *PluginLoaded {
loadedPlugin := PluginLoaded{}
// TODO: Make the help messages for users much friendlier
if !pluginExists(path) {
if isDevPlugin {
printer.Fatal(
fmt.Errorf("Plugin `%s` could not be found", path),
"Check the path you provided with --load-plugin is correct.",
"https://www.kombustion.io/api/cli/#load-plugin",
)
}
printer.Fatal(
fmt.Errorf("Plugin `%s` is not installed, but is included in kombustion.lock", name),
"Run `kombustion install` to fix.",
"",
)
}
loadedPlugin.InternalConfig.PathOnDisk = path
currentHash, err := getHashOfFile(path)
if err != nil {
printer.Fatal(
err,
fmt.Sprintf("Check user has permissions to read %s", path),
"",
)
}
if !isDevPlugin && currentHash != expectedHash {
printer.Fatal(
fmt.Errorf("Hash of plugin %s@%s does not match lock file", name, version),
"Reinstall the plugin by removing %s and running `kombustion install`",
"",
)
}
// Open the plugin
p, err := plugin.Open(path)
if err != nil {
printer.Fatal(
fmt.Errorf("Plugin `%s` could not be loaded, this is likely an issue with the plugin", name),
"Try your command again, but if it fails file an issue with the plugin author.",
"",
)
}
// Config
RegisterConstructor, _ := p.Lookup("Register")
configFunc := RegisterConstructor.(func() []byte)
config, err := loadConfig(configFunc())
if err != nil {
printer.Fatal(
fmt.Errorf("Plugin `%s` does not have a valid config", name),
"Try your command again, but if it fails file an issue with the plugin author.",
"",
)
}
validateConfig(config, name, version)
loadedPlugin.Config = config
loadedPlugin.InternalConfig.Prefix = config.Prefix
if alias != "" {
loadedPlugin.InternalConfig.Prefix = alias
}
// Load Parsers
parserConstructor, _ := p.Lookup("Parsers")
if parserConstructor != nil {
loadedPlugin.Parsers = parserConstructor.(*map[string]func(string, string) []byte)
}
return &loadedPlugin
}
// Helper function to ensure a plugin file exists before we attempt to load it
func pluginExists(filePath string) bool {
if _, err := os.Stat(filePath); !os.IsNotExist(err) {
return true
}
return false
}
func validateConfig(config pluginTypes.Config, pluginName string, pluginVersion string) {
// TODO: improve these error messages, and provide links to the docs for plugin devs
if config.Name == "" {
printer.Fatal(
fmt.Errorf("Plugin `%s` did not supply a name, this plugin cannot be loaded", pluginName),
"Try your command again, but if it fails file an issue with the plugin author.",
"",
)
}
switch config.Prefix {
case "":
printer.Fatal(
fmt.Errorf("Plugin `%s` did not supply a prefix, this plugin cannot be loaded", pluginName),
"Try your command again, but if it fails file an issue with the plugin author.",
"",
)
case "AWS":
printer.Fatal(
fmt.Errorf("Plugin `%s` tried to use 'AWS' as prefix, this plugin cannot be loaded", pluginName),
"'AWS' is a restricted prefix, and cannt be used by a plugin. This is an issue with the plugin.",
"",
)
case "Custom":
printer.Fatal(
fmt.Errorf("Plugin `%s` tried to use 'Custom' as prefix, this plugin cannot be loaded", pluginName),
"'Custom' is a restricted prefix, and cannt be used by a plugin. This is an issue with the plugin.",
"",
)
case "Kombustion":
printer.Fatal(
fmt.Errorf("Plugin `%s` tried to use 'Kombustion' as prefix, this plugin cannot be loaded", pluginName),
"'Kombustion' is a restricted prefix, and cannt be used by a plugin. This is an issue with the plugin.",
"",
)
}
}