-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add basic framework for writing a CLI plugin
That is, the helper to be used from the plugin's `main`. Also add a `helloworld` plugin example and build integration. Signed-off-by: Ian Campbell <ijc@docker.com>
- Loading branch information
Ian Campbell
committed
Jan 29, 2019
1 parent
8cf946d
commit e962404
Showing
10 changed files
with
248 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/docker/cli/cli-plugins/manager" | ||
"github.com/docker/cli/cli-plugins/plugin" | ||
"github.com/docker/cli/cli/command" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func main() { | ||
plugin.Run(func(dockerCli command.Cli) *cobra.Command { | ||
goodbye := &cobra.Command{ | ||
Use: "goodbye", | ||
Short: "Say Goodbye instead of Hello", | ||
Run: func(cmd *cobra.Command, _ []string) { | ||
fmt.Fprintln(dockerCli.Out(), "Goodbye World!") | ||
}, | ||
} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "helloworld", | ||
Short: "A basic Hello World plugin for tests", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
fmt.Fprintln(dockerCli.Out(), "Hello World!") | ||
}, | ||
} | ||
|
||
cmd.AddCommand(goodbye) | ||
return cmd | ||
}, | ||
manager.Metadata{ | ||
SchemaVersion: "0.1.0", | ||
Vendor: "Docker Inc.", | ||
Version: "0.1.0", | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package manager | ||
|
||
const ( | ||
// NamePrefix is the prefix required on all plugin binary names | ||
NamePrefix = "docker-" | ||
|
||
// MetadataSubcommandName is the name of the plugin subcommand | ||
// which must be supported by every plugin and returns the | ||
// plugin metadata. | ||
MetadataSubcommandName = "docker-cli-plugin-metadata" | ||
) | ||
|
||
// Metadata provided by the plugin | ||
type Metadata struct { | ||
// SchemaVersion describes the version of this struct. Mandatory, must be "0.1.0" | ||
SchemaVersion string | ||
// Vendor is the name of the plugin vendor. Mandatory | ||
Vendor string | ||
// Version is the optional version of this plugin. | ||
Version string | ||
// ShortDescription should be suitable for a single line help message. | ||
ShortDescription string | ||
// URL is a pointer to the plugin's homepage. | ||
URL string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package plugin | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/docker/cli/cli" | ||
"github.com/docker/cli/cli-plugins/manager" | ||
"github.com/docker/cli/cli/command" | ||
cliflags "github.com/docker/cli/cli/flags" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/pflag" | ||
) | ||
|
||
// Run is the top-level entry point to the CLI plugin framework. It should be called from your plugin's `main()` function. | ||
func Run(makeCmd func(command.Cli) *cobra.Command, meta manager.Metadata) { | ||
dockerCli, err := command.NewDockerCli() | ||
if err != nil { | ||
fmt.Fprintln(os.Stderr, err) | ||
os.Exit(1) | ||
} | ||
|
||
plugin := makeCmd(dockerCli) | ||
|
||
cmd := newPluginCommand(dockerCli, plugin, meta) | ||
|
||
if err := cmd.Execute(); err != nil { | ||
if sterr, ok := err.(cli.StatusError); ok { | ||
if sterr.Status != "" { | ||
fmt.Fprintln(dockerCli.Err(), sterr.Status) | ||
} | ||
// StatusError should only be used for errors, and all errors should | ||
// have a non-zero exit status, so never exit with 0 | ||
if sterr.StatusCode == 0 { | ||
os.Exit(1) | ||
} | ||
os.Exit(sterr.StatusCode) | ||
} | ||
fmt.Fprintln(dockerCli.Err(), err) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func newPluginCommand(dockerCli *command.DockerCli, plugin *cobra.Command, meta manager.Metadata) *cobra.Command { | ||
var ( | ||
opts *cliflags.ClientOptions | ||
flags *pflag.FlagSet | ||
) | ||
|
||
name := plugin.Use | ||
fullname := manager.NamePrefix + name | ||
|
||
cmd := &cobra.Command{ | ||
Use: fmt.Sprintf("docker [OPTIONS] %s [ARG...]", name), | ||
Short: fullname + " is a Docker CLI plugin", | ||
SilenceUsage: true, | ||
SilenceErrors: true, | ||
TraverseChildren: true, | ||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { | ||
// flags must be the top-level command flags, not cmd.Flags() | ||
opts.Common.SetDefaultOptions(flags) | ||
return dockerCli.Initialize(opts) | ||
}, | ||
DisableFlagsInUseLine: true, | ||
} | ||
opts, flags = cli.SetupPluginRootCommand(cmd) | ||
|
||
cmd.SetOutput(dockerCli.Out()) | ||
|
||
cmd.AddCommand( | ||
plugin, | ||
newMetadataSubcommand(plugin, meta), | ||
) | ||
|
||
cli.DisableFlagsInUseLine(cmd) | ||
|
||
return cmd | ||
} | ||
|
||
func newMetadataSubcommand(plugin *cobra.Command, meta manager.Metadata) *cobra.Command { | ||
if meta.ShortDescription == "" { | ||
meta.ShortDescription = plugin.Short | ||
} | ||
cmd := &cobra.Command{ | ||
Use: manager.MetadataSubcommandName, | ||
Hidden: true, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
enc := json.NewEncoder(os.Stdout) | ||
enc.SetEscapeHTML(false) | ||
enc.SetIndent("", " ") | ||
return enc.Encode(meta) | ||
}, | ||
} | ||
return cmd | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#!/usr/bin/env bash | ||
# | ||
# Build a static binary for the host OS/ARCH | ||
# | ||
|
||
set -eu -o pipefail | ||
|
||
source ./scripts/build/.variables | ||
|
||
mkdir -p "build/plugins-${GOOS}-${GOARCH}" | ||
for p in cli-plugins/examples/* ; do | ||
[ -d "$p" ] || continue | ||
|
||
n=$(basename "$p") | ||
|
||
TARGET="build/plugins-${GOOS}-${GOARCH}/docker-${n}" | ||
|
||
echo "Building statically linked $TARGET" | ||
export CGO_ENABLED=0 | ||
go build -o "${TARGET}" --ldflags "${LDFLAGS}" "github.com/docker/cli/${p}" | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#!/usr/bin/env bash | ||
# | ||
# Build a static binary for the host OS/ARCH | ||
# | ||
|
||
set -eu -o pipefail | ||
|
||
source ./scripts/build/.variables | ||
|
||
export CGO_ENABLED=1 | ||
export GOOS=darwin | ||
export GOARCH=amd64 | ||
export CC=o64-clang | ||
export CXX=o64-clang++ | ||
export LDFLAGS="$LDFLAGS -linkmode external -s" | ||
export LDFLAGS_STATIC_DOCKER='-extld='${CC} | ||
|
||
source ./scripts/build/plugins |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#!/usr/bin/env bash | ||
# | ||
# Build a static binary for the host OS/ARCH | ||
# | ||
|
||
set -eu -o pipefail | ||
|
||
source ./scripts/build/.variables | ||
export CC=x86_64-w64-mingw32-gcc | ||
export CGO_ENABLED=1 | ||
export GOOS=windows | ||
export GOARCH=amd64 | ||
|
||
source ./scripts/build/plugins |