Extensible Fission CLI (#743)

This PR introduces extensibility to the Fission CLI. The principle behind the design of this extensibility is taken from the approach git uses: the main binary (fission) calls other binaries (fission-workflows) - which it discovers using simple prefix-rules - based on specific commands (fission workflow <command>).
This commit is contained in:
Erwin van Eyk
2018-08-17 15:20:46 +08:00
committed by Ta-Ching Chen
parent ad28922871
commit 5c1d8bc90c
7 changed files with 606 additions and 13 deletions
+114 -13
View File
@@ -20,12 +20,16 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/ghodss/yaml"
"github.com/urfave/cli"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/fission/fission"
"github.com/fission/fission/fission/log"
"github.com/fission/fission/fission/plugin"
"github.com/fission/fission/fission/portforward"
"github.com/urfave/cli"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func getFissionNamespace() string {
@@ -77,17 +81,15 @@ func main() {
app.Name = "fission"
app.Usage = "Serverless functions for Kubernetes"
app.Version = fission.Version
cli.VersionPrinter = func(c *cli.Context) {
clientVer := fission.BuildInfo().String()
fmt.Printf("Client Version: %v\n", clientVer)
serverInfo, err := getClient(getServerUrl()).ServerInfo()
if err != nil {
fmt.Printf("Error getting Fission API version: %v", err)
} else {
serverVer := serverInfo.Build.String()
fmt.Printf("Server Version: %v\n", serverVer)
cli.VersionPrinter = versionPrinter
app.CustomAppHelpTemplate = helpTemplate
app.ExtraInfo = func() map[string]string {
info := map[string]string{}
for _, pmd := range plugin.FindAll() {
names := strings.Join(append([]string{pmd.Name}, pmd.Aliases...), ", ")
info[names] = pmd.Usage
}
return info
}
app.Flags = []cli.Flag{
@@ -310,8 +312,107 @@ func main() {
{Name: "package", Aliases: []string{"pkg"}, Usage: "Manage packages", Subcommands: pkgSubCommands},
{Name: "spec", Aliases: []string{"specs"}, Usage: "Manage a declarative app specification", Subcommands: specSubCommands},
{Name: "upgrade", Aliases: []string{}, Usage: "Upgrade tool from fission v0.1", Subcommands: upgradeSubCommands},
cmdPlugin,
}
app.Before = cliHook
app.CommandNotFound = handleCommandNotFound
app.Run(os.Args)
}
func handleCommandNotFound(ctx *cli.Context, subCommand string) {
pmd, err := plugin.Find(subCommand)
if err != nil {
switch err {
case plugin.ErrPluginNotFound:
url, ok := plugin.SearchRegistries(subCommand)
if !ok {
log.Fatal("No help topic for '" + subCommand + "'")
}
log.Fatal(fmt.Sprintf(`Command '%v' is not installed.
It is available to download at '%v'.
To install it for your local Fission CLI:
1. Download the plugin binary for your OS from the URL
2. Ensure that the plugin binary is executable: chmod +x <binary>
2. Add the plugin binary to your $PATH: mv <binary> /usr/local/bin/fission-%v`, subCommand, url, subCommand))
default:
log.Fatal("Error occurred when invoking " + subCommand + ": " + err.Error())
}
os.Exit(1)
}
// Rebuild global arguments string (urfave/cli does not have an option to get the raw input of the global flags)
var globalArgs []string
for _, globalFlagName := range ctx.GlobalFlagNames() {
val := fmt.Sprintf("%v", ctx.GlobalGeneric(globalFlagName))
if len(val) > 0 {
globalArgs = append(globalArgs, fmt.Sprintf("--%v", globalFlagName), val)
}
}
args := append(globalArgs, ctx.Args().Tail()...)
err = plugin.Exec(pmd, args)
if err != nil {
os.Exit(1)
}
}
// Versions is a container of versions of the client (and its plugins) and server (and its plugins).
type Versions struct {
Client map[string]fission.BuildMeta `json:"client"`
Server map[string]fission.BuildMeta `json:"server"`
}
func versionPrinter(_ *cli.Context) {
serverInfo, err := getClient(getServerUrl()).ServerInfo()
if err != nil {
log.Warn(fmt.Sprintf("Error getting Fission API version: %v", err))
}
// Fetch client versions
versions := Versions{
Client: map[string]fission.BuildMeta{
"fission/core": fission.BuildInfo(),
},
}
for _, pmd := range plugin.FindAll() {
versions.Client[pmd.Name] = fission.BuildMeta{
Version: pmd.Version,
}
}
// Fetch server versions
versions.Server = map[string]fission.BuildMeta{
"fission/core": serverInfo.Build,
}
// FUTURE: fetch versions of plugins server-side
bs, err := yaml.Marshal(versions)
if err != nil {
log.Fatal("Failed to format versions: " + err.Error())
}
fmt.Print(string(bs))
}
var helpTemplate = `NAME:
{{.Name}}{{if .Usage}} - {{.Usage}}{{end}}
USAGE:
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
VERSION:
{{.Version}}{{end}}{{end}}{{if .Description}}
DESCRIPTION:
{{.Description}}{{end}}{{if .VisibleCommands}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
{{.Name}}:{{end}}{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
PLUGIN COMMANDS:{{ range $name, $usage := ExtraInfo }}
{{$name}}{{"\t"}}{{$usage}}{{end}}
GLOBAL OPTIONS:
{{range $index, $option := .VisibleFlags}}{{if $index}}
{{end}}{{$option}}{{end}}{{end}}
`