Change to "compile-in" plugins
Move away from the builtin 'plugin' package in favor of compile-in plugins. This will require a plugin author to inject code into the proper packages before building airshipctl
This commit is contained in:
parent
f76eb8e027
commit
b5de5bf967
20
Makefile
20
Makefile
@ -5,12 +5,6 @@ EXECUTABLE_CLI := airshipctl
|
|||||||
|
|
||||||
SCRIPTS_DIR := scripts
|
SCRIPTS_DIR := scripts
|
||||||
|
|
||||||
PLUGIN_DIR := _plugins
|
|
||||||
PLUGIN_BIN := $(PLUGIN_DIR)/bin
|
|
||||||
PLUGIN_INT := $(patsubst $(PLUGIN_DIR)/internal/%,$(PLUGIN_BIN)/%.so,$(wildcard $(PLUGIN_DIR)/internal/*))
|
|
||||||
PLUGIN_EXT := $(wildcard $(PLUGIN_DIR)/external/*)
|
|
||||||
BINDATA := "github.com/shuLhan/go-bindata/cmd/go-bindata"
|
|
||||||
|
|
||||||
# linting
|
# linting
|
||||||
LINTER_CMD := "github.com/golangci/golangci-lint/cmd/golangci-lint" run
|
LINTER_CMD := "github.com/golangci/golangci-lint/cmd/golangci-lint" run
|
||||||
ADDTL_LINTERS := goconst,gofmt,lll,unparam
|
ADDTL_LINTERS := goconst,gofmt,lll,unparam
|
||||||
@ -26,7 +20,7 @@ MIN_COVERAGE := 70
|
|||||||
|
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: plugin
|
build:
|
||||||
@go build -o $(BINDIR)/$(EXECUTABLE_CLI)
|
@go build -o $(BINDIR)/$(EXECUTABLE_CLI)
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
@ -58,10 +52,6 @@ clean:
|
|||||||
@rm -fr $(BINDIR)
|
@rm -fr $(BINDIR)
|
||||||
@rm -fr $(COVER_FILE)
|
@rm -fr $(COVER_FILE)
|
||||||
|
|
||||||
.PHONY: plugin-clean
|
|
||||||
plugin-clean:
|
|
||||||
@rm -fr $(PLUGIN_BIN)
|
|
||||||
|
|
||||||
.PHONY: docs
|
.PHONY: docs
|
||||||
docs:
|
docs:
|
||||||
@echo "TODO"
|
@echo "TODO"
|
||||||
@ -71,11 +61,3 @@ update-golden: TESTFLAGS += -update -v
|
|||||||
update-golden: PKG = github.com/ian-howell/airshipctl/cmd
|
update-golden: PKG = github.com/ian-howell/airshipctl/cmd
|
||||||
update-golden:
|
update-golden:
|
||||||
@go test $(PKG) $(TESTFLAGS)
|
@go test $(PKG) $(TESTFLAGS)
|
||||||
|
|
||||||
.PHONY: plugin
|
|
||||||
plugin: $(PLUGIN_INT)
|
|
||||||
@for plugin in $(PLUGIN_EXT); do $(MAKE) -C $${plugin}; done
|
|
||||||
@go run $(BINDATA) $(PLUGIN_BIN)
|
|
||||||
|
|
||||||
$(PLUGIN_BIN)/%.so: $(PLUGIN_DIR)/*/%/*.go
|
|
||||||
@go build -buildmode=plugin -o $@ $^
|
|
||||||
|
2
_plugins/external/example/makefile
vendored
2
_plugins/external/example/makefile
vendored
@ -1,2 +0,0 @@
|
|||||||
all:
|
|
||||||
@go build -buildmode=plugin -o ../../bin/example.so example.go
|
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -7,13 +7,10 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint:deadcode,unused,unparam
|
func NewExampleCommand(out io.Writer, args []string) *cobra.Command {
|
||||||
func NewCommand(out io.Writer, args []string) *cobra.Command {
|
|
||||||
exampleCommand := &cobra.Command{
|
exampleCommand := &cobra.Command{
|
||||||
Use: "example",
|
Use: "example",
|
||||||
Short: "an example command",
|
Short: "an example command",
|
||||||
// Hidden is set to true because this is an example
|
|
||||||
Hidden: true,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Fprintln(out, "Hello world!")
|
fmt.Fprintln(out, "Hello world!")
|
||||||
},
|
},
|
19
cmd/plugins.go
Normal file
19
cmd/plugins.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
// builtinPlugins are the plugins that are built and maintained by the
|
||||||
|
// airshipctl team. They may be disabled if desired
|
||||||
|
var builtinPlugins = []func(io.Writer, []string) *cobra.Command{
|
||||||
|
NewWorkflowCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
// externalPlugins are external. The function to create a command should be
|
||||||
|
// placed here
|
||||||
|
var externalPlugins = []func(io.Writer, []string) *cobra.Command{
|
||||||
|
NewExampleCommand, // This is an example and shouldn't be enabled in production builds
|
||||||
|
}
|
47
cmd/root.go
47
cmd/root.go
@ -1,27 +1,21 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/ian-howell/airshipctl/pkg/environment"
|
"github.com/ian-howell/airshipctl/pkg/environment"
|
||||||
"github.com/ian-howell/airshipctl/pkg/log"
|
"github.com/ian-howell/airshipctl/pkg/log"
|
||||||
"github.com/ian-howell/airshipctl/pkg/plugin"
|
|
||||||
"github.com/ian-howell/airshipctl/pkg/util"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var settings environment.AirshipCTLSettings
|
var settings environment.AirshipCTLSettings
|
||||||
|
|
||||||
const defaultPluginDir = "_plugins/bin"
|
|
||||||
|
|
||||||
// NewRootCmd creates the root `airshipctl` command. All other commands are
|
// NewRootCmd creates the root `airshipctl` command. All other commands are
|
||||||
// subcommands branching from this one
|
// subcommands branching from this one
|
||||||
func NewRootCmd(out io.Writer, pluginDir string, args []string) (*cobra.Command, error) {
|
func NewRootCmd(out io.Writer, args []string) (*cobra.Command, error) {
|
||||||
rootCmd := &cobra.Command{
|
rootCmd := &cobra.Command{
|
||||||
Use: "airshipctl",
|
Use: "airshipctl",
|
||||||
Short: "airshipctl is a unified entrypoint to various airship components",
|
Short: "airshipctl is a unified entrypoint to various airship components",
|
||||||
@ -33,21 +27,7 @@ func NewRootCmd(out io.Writer, pluginDir string, args []string) (*cobra.Command,
|
|||||||
|
|
||||||
rootCmd.AddCommand(NewVersionCommand(out))
|
rootCmd.AddCommand(NewVersionCommand(out))
|
||||||
|
|
||||||
if _, err := os.Stat(pluginDir); err == nil {
|
loadPluginCommands(rootCmd, out, args)
|
||||||
pluginFiles, err := util.ReadDir(pluginDir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("could not read plugins: " + err.Error())
|
|
||||||
}
|
|
||||||
for _, pluginFile := range pluginFiles {
|
|
||||||
pathToPlugin := filepath.Join(pluginDir, pluginFile.Name())
|
|
||||||
newCommand, err := plugin.CreateCommandFromPlugin(pathToPlugin, out, args)
|
|
||||||
if err != nil {
|
|
||||||
log.Debugf("Could not load plugin from %s: %s\n", pathToPlugin, err.Error())
|
|
||||||
} else {
|
|
||||||
rootCmd.AddCommand(newCommand)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Init(&settings, out)
|
log.Init(&settings, out)
|
||||||
|
|
||||||
@ -56,14 +36,25 @@ func NewRootCmd(out io.Writer, pluginDir string, args []string) (*cobra.Command,
|
|||||||
|
|
||||||
// Execute runs the base airshipctl command
|
// Execute runs the base airshipctl command
|
||||||
func Execute(out io.Writer) {
|
func Execute(out io.Writer) {
|
||||||
rootCmd, err := NewRootCmd(out, defaultPluginDir, os.Args[1:])
|
rootCmd, err := NewRootCmd(out, os.Args[1:])
|
||||||
osExitIfError(out, err)
|
|
||||||
osExitIfError(out, rootCmd.Execute())
|
|
||||||
}
|
|
||||||
|
|
||||||
func osExitIfError(out io.Writer, err error) {
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(out, err)
|
fmt.Fprintln(out, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
fmt.Fprintln(out, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadPluginCommands finds all of the plugins in the builtinPlugins and
|
||||||
|
// externalPlugins datastructures, and loads them as subcommands to cmd
|
||||||
|
func loadPluginCommands(cmd *cobra.Command, out io.Writer, args []string) {
|
||||||
|
for _, subcmd := range builtinPlugins {
|
||||||
|
cmd.AddCommand(subcmd(out, args))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, subcmd := range externalPlugins {
|
||||||
|
cmd.AddCommand(subcmd(out, args))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,10 @@ Usage:
|
|||||||
airshipctl [command]
|
airshipctl [command]
|
||||||
|
|
||||||
Available Commands:
|
Available Commands:
|
||||||
|
example an example command
|
||||||
help Help about any command
|
help Help about any command
|
||||||
version Show the version number of airshipctl
|
version Show the version number of airshipctl
|
||||||
|
workflow access to workflows
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
--debug enable verbose output
|
--debug enable verbose output
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@ -6,11 +6,9 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint:unused
|
|
||||||
var kubeConfigFilePath string
|
var kubeConfigFilePath string
|
||||||
|
|
||||||
//nolint:deadcode,unused
|
func NewWorkflowCommand(out io.Writer, args []string) *cobra.Command {
|
||||||
func NewCommand(out io.Writer, args []string) *cobra.Command {
|
|
||||||
workflowRootCmd := &cobra.Command{
|
workflowRootCmd := &cobra.Command{
|
||||||
Use: "workflow",
|
Use: "workflow",
|
||||||
Short: "access to workflows",
|
Short: "access to workflows",
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -13,7 +13,6 @@ import (
|
|||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint:unused
|
|
||||||
func NewWorkflowListCommand(out io.Writer, args []string) *cobra.Command {
|
func NewWorkflowListCommand(out io.Writer, args []string) *cobra.Command {
|
||||||
|
|
||||||
// TODO(howell): This is only used to appease the linter. It will be used later
|
// TODO(howell): This is only used to appease the linter. It will be used later
|
@ -42,7 +42,7 @@ func executeCmd(t *testing.T, command string) []byte {
|
|||||||
var actual bytes.Buffer
|
var actual bytes.Buffer
|
||||||
// TODO(howell): switch to shellwords (or similar)
|
// TODO(howell): switch to shellwords (or similar)
|
||||||
args := strings.Fields(command)
|
args := strings.Fields(command)
|
||||||
rootCmd, err := cmd.NewRootCmd(&actual, "testdata/_plugins/bin", args)
|
rootCmd, err := cmd.NewRootCmd(&actual, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(err.Error())
|
t.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user