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
|
||||
|
||||
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
|
||||
LINTER_CMD := "github.com/golangci/golangci-lint/cmd/golangci-lint" run
|
||||
ADDTL_LINTERS := goconst,gofmt,lll,unparam
|
||||
@ -26,7 +20,7 @@ MIN_COVERAGE := 70
|
||||
|
||||
|
||||
.PHONY: build
|
||||
build: plugin
|
||||
build:
|
||||
@go build -o $(BINDIR)/$(EXECUTABLE_CLI)
|
||||
|
||||
.PHONY: test
|
||||
@ -58,10 +52,6 @@ clean:
|
||||
@rm -fr $(BINDIR)
|
||||
@rm -fr $(COVER_FILE)
|
||||
|
||||
.PHONY: plugin-clean
|
||||
plugin-clean:
|
||||
@rm -fr $(PLUGIN_BIN)
|
||||
|
||||
.PHONY: docs
|
||||
docs:
|
||||
@echo "TODO"
|
||||
@ -71,11 +61,3 @@ update-golden: TESTFLAGS += -update -v
|
||||
update-golden: PKG = github.com/ian-howell/airshipctl/cmd
|
||||
update-golden:
|
||||
@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 (
|
||||
"fmt"
|
||||
@ -7,13 +7,10 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
//nolint:deadcode,unused,unparam
|
||||
func NewCommand(out io.Writer, args []string) *cobra.Command {
|
||||
func NewExampleCommand(out io.Writer, args []string) *cobra.Command {
|
||||
exampleCommand := &cobra.Command{
|
||||
Use: "example",
|
||||
Short: "an example command",
|
||||
// Hidden is set to true because this is an example
|
||||
Hidden: true,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
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
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ian-howell/airshipctl/pkg/environment"
|
||||
"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"
|
||||
)
|
||||
|
||||
var settings environment.AirshipCTLSettings
|
||||
|
||||
const defaultPluginDir = "_plugins/bin"
|
||||
|
||||
// NewRootCmd creates the root `airshipctl` command. All other commands are
|
||||
// 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{
|
||||
Use: "airshipctl",
|
||||
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))
|
||||
|
||||
if _, err := os.Stat(pluginDir); err == nil {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
loadPluginCommands(rootCmd, out, args)
|
||||
|
||||
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
|
||||
func Execute(out io.Writer) {
|
||||
rootCmd, err := NewRootCmd(out, defaultPluginDir, os.Args[1:])
|
||||
osExitIfError(out, err)
|
||||
osExitIfError(out, rootCmd.Execute())
|
||||
}
|
||||
|
||||
func osExitIfError(out io.Writer, err error) {
|
||||
rootCmd, err := NewRootCmd(out, os.Args[1:])
|
||||
if err != nil {
|
||||
fmt.Fprintln(out, err)
|
||||
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]
|
||||
|
||||
Available Commands:
|
||||
example an example command
|
||||
help Help about any command
|
||||
version Show the version number of airshipctl
|
||||
workflow access to workflows
|
||||
|
||||
Flags:
|
||||
--debug enable verbose output
|
||||
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
@ -6,11 +6,9 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
//nolint:unused
|
||||
var kubeConfigFilePath string
|
||||
|
||||
//nolint:deadcode,unused
|
||||
func NewCommand(out io.Writer, args []string) *cobra.Command {
|
||||
func NewWorkflowCommand(out io.Writer, args []string) *cobra.Command {
|
||||
workflowRootCmd := &cobra.Command{
|
||||
Use: "workflow",
|
||||
Short: "access to workflows",
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -13,7 +13,6 @@ import (
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
//nolint:unused
|
||||
func NewWorkflowListCommand(out io.Writer, args []string) *cobra.Command {
|
||||
|
||||
// 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
|
||||
// TODO(howell): switch to shellwords (or similar)
|
||||
args := strings.Fields(command)
|
||||
rootCmd, err := cmd.NewRootCmd(&actual, "testdata/_plugins/bin", args)
|
||||
rootCmd, err := cmd.NewRootCmd(&actual, args)
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user