MM-11366: support a plugin bundle with multiple executables (#9121)
This avoids the need to distribute multiple plugins per architecture.
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
f2c1803905
Коммит
e718d2544f
@@ -120,13 +120,30 @@ type Manifest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ManifestBackend struct {
|
type ManifestBackend struct {
|
||||||
// The path to your executable binary. This should be relative to the root of your bundle and the
|
// Executables are the paths to your executable binaries, specifying multiple entry points
|
||||||
// location of the manifest file.
|
// for different platforms when bundled together in a single plugin.
|
||||||
|
Executables *ManifestExecutables `json:"executables,omitempty" yaml:"executables,omitempty"`
|
||||||
|
|
||||||
|
// Executable is the path to your executable binary. This should be relative to the root
|
||||||
|
// of your bundle and the location of the manifest file.
|
||||||
//
|
//
|
||||||
// On Windows, this file must have a ".exe" extension.
|
// On Windows, this file must have a ".exe" extension.
|
||||||
|
//
|
||||||
|
// If your plugin is compiled for multiple platforms, consider bundling them together
|
||||||
|
// and using the Executables field instead.
|
||||||
Executable string `json:"executable" yaml:"executable"`
|
Executable string `json:"executable" yaml:"executable"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ManifestExecutables struct {
|
||||||
|
// LinuxAmd64 is the path to your executable binary for the corresponding platform
|
||||||
|
LinuxAmd64 string `json:"linux-amd64,omitempty" yaml:"linux-amd64,omitempty"`
|
||||||
|
// DarwinAmd64 is the path to your executable binary for the corresponding platform
|
||||||
|
DarwinAmd64 string `json:"darwin-amd64,omitempty" yaml:"darwin-amd64,omitempty"`
|
||||||
|
// WindowsAmd64 is the path to your executable binary for the corresponding platform
|
||||||
|
// This file must have a ".exe" extension
|
||||||
|
WindowsAmd64 string `json:"windows-amd64,omitempty" yaml:"windows-amd64,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type ManifestWebapp struct {
|
type ManifestWebapp struct {
|
||||||
// The path to your webapp bundle. This should be relative to the root of your bundle and the
|
// The path to your webapp bundle. This should be relative to the root of your bundle and the
|
||||||
// location of the manifest file.
|
// location of the manifest file.
|
||||||
@@ -173,6 +190,34 @@ func (m *Manifest) ClientManifest() *Manifest {
|
|||||||
return cm
|
return cm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetExecutableForRuntime returns the path to the executable for the given runtime architecture.
|
||||||
|
//
|
||||||
|
// If the manifest defines multiple executables, but none match, or if only a single executable
|
||||||
|
// is defined, the Executable field will be returned. This method does not guarantee that the
|
||||||
|
// resulting binary can actually execute on the given platform.
|
||||||
|
func (m *Manifest) GetExecutableForRuntime(goOs, goArch string) string {
|
||||||
|
if m.Backend == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var executable string
|
||||||
|
if m.Backend.Executables != nil {
|
||||||
|
if goOs == "linux" && goArch == "amd64" {
|
||||||
|
executable = m.Backend.Executables.LinuxAmd64
|
||||||
|
} else if goOs == "darwin" && goArch == "amd64" {
|
||||||
|
executable = m.Backend.Executables.DarwinAmd64
|
||||||
|
} else if goOs == "windows" && goArch == "amd64" {
|
||||||
|
executable = m.Backend.Executables.WindowsAmd64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if executable == "" {
|
||||||
|
executable = m.Backend.Executable
|
||||||
|
}
|
||||||
|
|
||||||
|
return executable
|
||||||
|
}
|
||||||
|
|
||||||
// FindManifest will find and parse the manifest in a given directory.
|
// FindManifest will find and parse the manifest in a given directory.
|
||||||
//
|
//
|
||||||
// In all cases other than a does-not-exist error, path is set to the path of the manifest file that was
|
// In all cases other than a does-not-exist error, path is set to the path of the manifest file that was
|
||||||
|
|||||||
@@ -66,6 +66,11 @@ func TestManifestUnmarshal(t *testing.T) {
|
|||||||
Id: "theid",
|
Id: "theid",
|
||||||
Backend: &ManifestBackend{
|
Backend: &ManifestBackend{
|
||||||
Executable: "theexecutable",
|
Executable: "theexecutable",
|
||||||
|
Executables: &ManifestExecutables{
|
||||||
|
LinuxAmd64: "theexecutable-linux-amd64",
|
||||||
|
DarwinAmd64: "theexecutable-darwin-amd64",
|
||||||
|
WindowsAmd64: "theexecutable-windows-amd64",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Webapp: &ManifestWebapp{
|
Webapp: &ManifestWebapp{
|
||||||
BundlePath: "thebundlepath",
|
BundlePath: "thebundlepath",
|
||||||
@@ -98,6 +103,10 @@ func TestManifestUnmarshal(t *testing.T) {
|
|||||||
id: theid
|
id: theid
|
||||||
backend:
|
backend:
|
||||||
executable: theexecutable
|
executable: theexecutable
|
||||||
|
executables:
|
||||||
|
linux-amd64: theexecutable-linux-amd64
|
||||||
|
darwin-amd64: theexecutable-darwin-amd64
|
||||||
|
windows-amd64: theexecutable-windows-amd64
|
||||||
webapp:
|
webapp:
|
||||||
bundle_path: thebundlepath
|
bundle_path: thebundlepath
|
||||||
settings_schema:
|
settings_schema:
|
||||||
@@ -121,7 +130,12 @@ settings_schema:
|
|||||||
require.NoError(t, json.Unmarshal([]byte(`{
|
require.NoError(t, json.Unmarshal([]byte(`{
|
||||||
"id": "theid",
|
"id": "theid",
|
||||||
"backend": {
|
"backend": {
|
||||||
"executable": "theexecutable"
|
"executable": "theexecutable",
|
||||||
|
"executables": {
|
||||||
|
"linux-amd64": "theexecutable-linux-amd64",
|
||||||
|
"darwin-amd64": "theexecutable-darwin-amd64",
|
||||||
|
"windows-amd64": "theexecutable-windows-amd64"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"webapp": {
|
"webapp": {
|
||||||
"bundle_path": "thebundlepath"
|
"bundle_path": "thebundlepath"
|
||||||
@@ -283,3 +297,154 @@ func TestManifestClientManifest(t *testing.T) {
|
|||||||
assert.NotEmpty(t, manifest.Backend)
|
assert.NotEmpty(t, manifest.Backend)
|
||||||
assert.NotEmpty(t, manifest.SettingsSchema)
|
assert.NotEmpty(t, manifest.SettingsSchema)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestManifestGetExecutableForRuntime(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
Description string
|
||||||
|
Manifest *Manifest
|
||||||
|
GoOs string
|
||||||
|
GoArch string
|
||||||
|
ExpectedExecutable string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"no backend",
|
||||||
|
&Manifest{},
|
||||||
|
"linux",
|
||||||
|
"amd64",
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"no executable",
|
||||||
|
&Manifest{
|
||||||
|
Backend: &ManifestBackend{},
|
||||||
|
},
|
||||||
|
"linux",
|
||||||
|
"amd64",
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"single executable",
|
||||||
|
&Manifest{
|
||||||
|
Backend: &ManifestBackend{
|
||||||
|
Executable: "path/to/executable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"linux",
|
||||||
|
"amd64",
|
||||||
|
"path/to/executable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"single executable, different runtime",
|
||||||
|
&Manifest{
|
||||||
|
Backend: &ManifestBackend{
|
||||||
|
Executable: "path/to/executable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"darwin",
|
||||||
|
"amd64",
|
||||||
|
"path/to/executable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"multiple executables, no match",
|
||||||
|
&Manifest{
|
||||||
|
Backend: &ManifestBackend{
|
||||||
|
Executables: &ManifestExecutables{
|
||||||
|
LinuxAmd64: "linux-amd64/path/to/executable",
|
||||||
|
DarwinAmd64: "darwin-amd64/path/to/executable",
|
||||||
|
WindowsAmd64: "windows-amd64/path/to/executable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"other",
|
||||||
|
"amd64",
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"multiple executables, linux-amd64 match",
|
||||||
|
&Manifest{
|
||||||
|
Backend: &ManifestBackend{
|
||||||
|
Executables: &ManifestExecutables{
|
||||||
|
LinuxAmd64: "linux-amd64/path/to/executable",
|
||||||
|
DarwinAmd64: "darwin-amd64/path/to/executable",
|
||||||
|
WindowsAmd64: "windows-amd64/path/to/executable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"linux",
|
||||||
|
"amd64",
|
||||||
|
"linux-amd64/path/to/executable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"multiple executables, linux-amd64 match, single executable ignored",
|
||||||
|
&Manifest{
|
||||||
|
Backend: &ManifestBackend{
|
||||||
|
Executables: &ManifestExecutables{
|
||||||
|
LinuxAmd64: "linux-amd64/path/to/executable",
|
||||||
|
DarwinAmd64: "darwin-amd64/path/to/executable",
|
||||||
|
WindowsAmd64: "windows-amd64/path/to/executable",
|
||||||
|
},
|
||||||
|
Executable: "path/to/executable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"linux",
|
||||||
|
"amd64",
|
||||||
|
"linux-amd64/path/to/executable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"multiple executables, darwin-amd64 match",
|
||||||
|
&Manifest{
|
||||||
|
Backend: &ManifestBackend{
|
||||||
|
Executables: &ManifestExecutables{
|
||||||
|
LinuxAmd64: "linux-amd64/path/to/executable",
|
||||||
|
DarwinAmd64: "darwin-amd64/path/to/executable",
|
||||||
|
WindowsAmd64: "windows-amd64/path/to/executable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"darwin",
|
||||||
|
"amd64",
|
||||||
|
"darwin-amd64/path/to/executable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"multiple executables, windows-amd64 match",
|
||||||
|
&Manifest{
|
||||||
|
Backend: &ManifestBackend{
|
||||||
|
Executables: &ManifestExecutables{
|
||||||
|
LinuxAmd64: "linux-amd64/path/to/executable",
|
||||||
|
DarwinAmd64: "darwin-amd64/path/to/executable",
|
||||||
|
WindowsAmd64: "windows-amd64/path/to/executable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"windows",
|
||||||
|
"amd64",
|
||||||
|
"windows-amd64/path/to/executable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"multiple executables, no match, single executable fallback",
|
||||||
|
&Manifest{
|
||||||
|
Backend: &ManifestBackend{
|
||||||
|
Executables: &ManifestExecutables{
|
||||||
|
LinuxAmd64: "linux-amd64/path/to/executable",
|
||||||
|
DarwinAmd64: "darwin-amd64/path/to/executable",
|
||||||
|
WindowsAmd64: "windows-amd64/path/to/executable",
|
||||||
|
},
|
||||||
|
Executable: "path/to/executable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"other",
|
||||||
|
"amd64",
|
||||||
|
"path/to/executable",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.Description, func(t *testing.T) {
|
||||||
|
assert.Equal(
|
||||||
|
t,
|
||||||
|
testCase.ExpectedExecutable,
|
||||||
|
testCase.Manifest.GetExecutableForRuntime(testCase.GoOs, testCase.GoArch),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -39,7 +40,10 @@ func newSupervisor(pluginInfo *model.BundleInfo, parentLogger *mlog.Logger, apiI
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
executable := filepath.Clean(filepath.Join(".", pluginInfo.Manifest.Backend.Executable))
|
executable := filepath.Clean(filepath.Join(
|
||||||
|
".",
|
||||||
|
pluginInfo.Manifest.GetExecutableForRuntime(runtime.GOOS, runtime.GOARCH),
|
||||||
|
))
|
||||||
if strings.HasPrefix(executable, "..") {
|
if strings.HasPrefix(executable, "..") {
|
||||||
return nil, fmt.Errorf("invalid backend executable")
|
return nil, fmt.Errorf("invalid backend executable")
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user