Commit 3ca94be2 authored by Anthony Fok's avatar Anthony Fok

New upstream version 0.1.15

parents
version: 2
jobs:
build:
docker:
- image: circleci/golang:1.10
working_directory: /go/src/github.com/alecthomas/kong
steps:
- checkout
- run:
name: Prepare
command: |
go get -v github.com/jstemmer/go-junit-report
go get -v -t -d ./...
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s v1.10.2
mkdir ~/report
when: always
- run:
name: Lint
command: |
./bin/golangci-lint run
- run:
name: Test
command: |
go test -v ./... 2>&1 | tee report.txt && go-junit-report report.txt > ~/report/junit.xml
- store_test_results:
path: ~/report
run:
tests: true
output:
print-issued-lines: false
linters:
enable-all: true
disable:
- maligned
- lll
linters-settings:
govet:
check-shadowing: true
gocyclo:
min-complexity: 10
dupl:
threshold: 100
goconst:
min-len: 5
min-occurrences: 3
gocyclo:
min-complexity: 20
issues:
max-per-linter: 0
max-same: 0
exclude-use-default: false
exclude:
- '^(G104|G204):'
# Very commonly not checked.
- 'Error return value of .(.*\.Help|.*\.MarkFlagRequired|(os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked'
- 'exported method (.*\.MarshalJSON|.*\.UnmarshalJSON) should have comment or be unexported'
- 'composite literal uses unkeyed fields'
- 'bad syntax for struct tag key'
- 'bad syntax for struct tag pair'
This diff is collapsed.
# Large-scale composed CLI
This directory illustrates how a large-scale CLI app could be structured.
// nolint
package main
import "fmt"
type AttachCmd struct {
DetachKeys string `help:"Override the key sequence for detaching a container"`
NoStdin bool `help:"Do not attach STDIN"`
SigProxy bool `help:"Proxy all received signals to the process" default:"true"`
Container string `arg required help:"Container ID to attach to."`
}
func (a *AttachCmd) Run(globals *Globals) error {
fmt.Printf("Config: %s\n", globals.Config)
fmt.Printf("Attaching to: %v\n", a.Container)
fmt.Printf("SigProxy: %v\n", a.SigProxy)
return nil
}
type BuildCmd struct {
Arg string `arg required`
}
func (cmd *BuildCmd) Run(globals *Globals) error {
return nil
}
type CommitCmd struct {
Arg string `arg required`
}
func (cmd *CommitCmd) Run(globals *Globals) error {
return nil
}
type CpCmd struct {
Arg string `arg required`
}
func (cmd *CpCmd) Run(globals *Globals) error {
return nil
}
type CreateCmd struct {
Arg string `arg required`
}
func (cmd *CreateCmd) Run(globals *Globals) error {
return nil
}
type DeployCmd struct {
Arg string `arg required`
}
func (cmd *DeployCmd) Run(globals *Globals) error {
return nil
}
type DiffCmd struct {
Arg string `arg required`
}
func (cmd *DiffCmd) Run(globals *Globals) error {
return nil
}
type EventsCmd struct {
Arg string `arg required`
}
func (cmd *EventsCmd) Run(globals *Globals) error {
return nil
}
type ExecCmd struct {
Arg string `arg required`
}
func (cmd *ExecCmd) Run(globals *Globals) error {
return nil
}
type ExportCmd struct {
Arg string `arg required`
}
func (cmd *ExportCmd) Run(globals *Globals) error {
return nil
}
type HistoryCmd struct {
Arg string `arg required`
}
func (cmd *HistoryCmd) Run(globals *Globals) error {
return nil
}
type ImagesCmd struct {
Arg string `arg required`
}
func (cmd *ImagesCmd) Run(globals *Globals) error {
return nil
}
type ImportCmd struct {
Arg string `arg required`
}
func (cmd *ImportCmd) Run(globals *Globals) error {
return nil
}
type InfoCmd struct {
Arg string `arg required`
}
func (cmd *InfoCmd) Run(globals *Globals) error {
return nil
}
type InspectCmd struct {
Arg string `arg required`
}
func (cmd *InspectCmd) Run(globals *Globals) error {
return nil
}
type KillCmd struct {
Arg string `arg required`
}
func (cmd *KillCmd) Run(globals *Globals) error {
return nil
}
type LoadCmd struct {
Arg string `arg required`
}
func (cmd *LoadCmd) Run(globals *Globals) error {
return nil
}
type LoginCmd struct {
Arg string `arg required`
}
func (cmd *LoginCmd) Run(globals *Globals) error {
return nil
}
type LogoutCmd struct {
Arg string `arg required`
}
func (cmd *LogoutCmd) Run(globals *Globals) error {
return nil
}
type LogsCmd struct {
Arg string `arg required`
}
func (cmd *LogsCmd) Run(globals *Globals) error {
return nil
}
type PauseCmd struct {
Arg string `arg required`
}
func (cmd *PauseCmd) Run(globals *Globals) error {
return nil
}
type PortCmd struct {
Arg string `arg required`
}
func (cmd *PortCmd) Run(globals *Globals) error {
return nil
}
type PsCmd struct {
Arg string `arg required`
}
func (cmd *PsCmd) Run(globals *Globals) error {
return nil
}
type PullCmd struct {
Arg string `arg required`
}
func (cmd *PullCmd) Run(globals *Globals) error {
return nil
}
type PushCmd struct {
Arg string `arg required`
}
func (cmd *PushCmd) Run(globals *Globals) error {
return nil
}
type RenameCmd struct {
Arg string `arg required`
}
func (cmd *RenameCmd) Run(globals *Globals) error {
return nil
}
type RestartCmd struct {
Arg string `arg required`
}
func (cmd *RestartCmd) Run(globals *Globals) error {
return nil
}
type RmCmd struct {
Arg string `arg required`
}
func (cmd *RmCmd) Run(globals *Globals) error {
return nil
}
type RmiCmd struct {
Arg string `arg required`
}
func (cmd *RmiCmd) Run(globals *Globals) error {
return nil
}
type RunCmd struct {
Arg string `arg required`
}
func (cmd *RunCmd) Run(globals *Globals) error {
return nil
}
type SaveCmd struct {
Arg string `arg required`
}
func (cmd *SaveCmd) Run(globals *Globals) error {
return nil
}
type SearchCmd struct {
Arg string `arg required`
}
func (cmd *SearchCmd) Run(globals *Globals) error {
return nil
}
type StartCmd struct {
Arg string `arg required`
}
func (cmd *StartCmd) Run(globals *Globals) error {
return nil
}
type StatsCmd struct {
Arg string `arg required`
}
func (cmd *StatsCmd) Run(globals *Globals) error {
return nil
}
type StopCmd struct {
Arg string `arg required`
}
func (cmd *StopCmd) Run(globals *Globals) error {
return nil
}
type TagCmd struct {
Arg string `arg required`
}
func (cmd *TagCmd) Run(globals *Globals) error {
return nil
}
type TopCmd struct {
Arg string `arg required`
}
func (cmd *TopCmd) Run(globals *Globals) error {
return nil
}
type UnpauseCmd struct {
Arg string `arg required`
}
func (cmd *UnpauseCmd) Run(globals *Globals) error {
return nil
}
type UpdateCmd struct {
Arg string `arg required`
}
func (cmd *UpdateCmd) Run(globals *Globals) error {
return nil
}
type VersionCmd struct {
Arg string `arg required`
}
func (cmd *VersionCmd) Run(globals *Globals) error {
return nil
}
type WaitCmd struct {
Arg string `arg required`
}
func (cmd *WaitCmd) Run(globals *Globals) error {
return nil
}
// nolint
package main
import (
"fmt"
"github.com/alecthomas/kong"
)
type Globals struct {
Config string `help:"Location of client config files" default:"~/.docker" type:"path"`
Debug bool `short:"D" help:"Enable debug mode"`
Host []string `short:"H" help:"Daemon socket(s) to connect to"`
LogLevel string `short:"l" help:"Set the logging level (debug|info|warn|error|fatal)" default:"info"`
TLS bool `help:"Use TLS; implied by --tls-verify"`
TLSCACert string `name:"tls-ca-cert" help:"Trust certs signed only by this CA" default:"~/.docker/ca.pem" type:"path"`
TLSCert string `help:"Path to TLS certificate file" default:"~/.docker/cert.pem" type:"path"`
TLSKey string `help:"Path to TLS key file" default:"~/.docker/key.pem" type:"path"`
TLSVerify bool `help:"Use TLS and verify the remote"`
Version VersionFlag `name:"version" help:"Print version information and quit"`
}
type VersionFlag string
func (v VersionFlag) Decode(ctx *kong.DecodeContext) error { return nil }
func (v VersionFlag) IsBool() bool { return true }
func (v VersionFlag) BeforeApply(app *kong.Kong, vars kong.Vars) error {
fmt.Println(vars["version"])
app.Exit(0)
return nil
}
type CLI struct {
Globals
Attach AttachCmd `cmd help:"Attach local standard input, output, and error streams to a running container"`
Build BuildCmd `cmd help:"Build an image from a Dockerfile"`
Commit CommitCmd `cmd help:"Create a new image from a container's changes"`
Cp CpCmd `cmd help:"Copy files/folders between a container and the local filesystem"`
Create CreateCmd `cmd help:"Create a new container"`
Deploy DeployCmd `cmd help:"Deploy a new stack or update an existing stack"`
Diff DiffCmd `cmd help:"Inspect changes to files or directories on a container's filesystem"`
Events EventsCmd `cmd help:"Get real time events from the server"`
Exec ExecCmd `cmd help:"Run a command in a running container"`
Export ExportCmd `cmd help:"Export a container's filesystem as a tar archive"`
History HistoryCmd `cmd help:"Show the history of an image"`
Images ImagesCmd `cmd help:"List images"`
Import ImportCmd `cmd help:"Import the contents from a tarball to create a filesystem image"`
Info InfoCmd `cmd help:"Display system-wide information"`
Inspect InspectCmd `cmd help:"Return low-level information on Docker objects"`
Kill KillCmd `cmd help:"Kill one or more running containers"`
Load LoadCmd `cmd help:"Load an image from a tar archive or STDIN"`
Login LoginCmd `cmd help:"Log in to a Docker registry"`
Logout LogoutCmd `cmd help:"Log out from a Docker registry"`
Logs LogsCmd `cmd help:"Fetch the logs of a container"`
Pause PauseCmd `cmd help:"Pause all processes within one or more containers"`
Port PortCmd `cmd help:"List port mappings or a specific mapping for the container"`
Ps PsCmd `cmd help:"List containers"`
Pull PullCmd `cmd help:"Pull an image or a repository from a registry"`
Push PushCmd `cmd help:"Push an image or a repository to a registry"`
Rename RenameCmd `cmd help:"Rename a container"`
Restart RestartCmd `cmd help:"Restart one or more containers"`
Rm RmCmd `cmd help:"Remove one or more containers"`
Rmi RmiCmd `cmd help:"Remove one or more images"`
Run RunCmd `cmd help:"Run a command in a new container"`
Save SaveCmd `cmd help:"Save one or more images to a tar archive (streamed to STDOUT by default)"`
Search SearchCmd `cmd help:"Search the Docker Hub for images"`
Start StartCmd `cmd help:"Start one or more stopped containers"`
Stats StatsCmd `cmd help:"Display a live stream of container(s) resource usage statistics"`
Stop StopCmd `cmd help:"Stop one or more running containers"`
Tag TagCmd `cmd help:"Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE"`
Top TopCmd `cmd help:"Display the running processes of a container"`
Unpause UnpauseCmd `cmd help:"Unpause all processes within one or more containers"`
Update UpdateCmd `cmd help:"Update configuration of one or more containers"`
Version VersionCmd `cmd help:"Show the Docker version information"`
Wait WaitCmd `cmd help:"Block until one or more containers stop, then print their exit codes"`
}
func main() {
cli := CLI{
Globals: Globals{
Version: VersionFlag("0.1.1"),
},
}
ctx := kong.Parse(&cli,
kong.Name("docker"),
kong.Description("A self-sufficient runtime for containers"),
kong.UsageOnError(),
kong.ConfigureHelp(kong.HelpOptions{
Compact: true,
}),
kong.Vars{
"version": "0.0.1",
})
err := ctx.Run(&cli.Globals)
ctx.FatalIfErrorf(err)
}
// nolint: govet
package main
import (
"fmt"
"github.com/alecthomas/kong"
)
// Ensure the grammar compiles.
var _ = kong.Must(&grammar{})
// Server interface.
type grammar struct {
Help helpCmd `cmd help:"Show help."`
Question helpCmd `cmd hidden name:"?" help:"Show help."`
Status statusCmd `cmd help:"Show server status."`
}
type statusCmd struct {
Verbose bool `short:"v" help:"Show verbose status information."`
}
func (s *statusCmd) Run(ctx *kong.Context) error {
ctx.Printf("OK")
return nil
}
type helpCmd struct {
Command []string `arg optional help:"Show help on command."`
}
// Run shows help.
func (h *helpCmd) Run(realCtx *kong.Context) error {
ctx, err := kong.Trace(realCtx.Kong, h.Command)
if err != nil {
return err
}
if ctx.Error != nil {
return ctx.Error
}
err = ctx.PrintUsage(false)
if err != nil {
return err
}
fmt.Fprintln(realCtx.Stdout)
return nil
}
package main
import (
"errors"
"fmt"
"io"
"log"
"os"
"strings"
"github.com/chzyer/readline"
"github.com/gliderlabs/ssh"
"github.com/google/shlex"
"github.com/kr/pty"
"golang.org/x/crypto/ssh/terminal"
"github.com/alecthomas/colour"
"github.com/alecthomas/kong"
)
type context struct {
kong *kong.Context
rl *readline.Instance
}
func handle(log *log.Logger, s ssh.Session) error {
log.Printf("New SSH")
sshPty, _, isPty := s.Pty()
if !isPty {
return errors.New("No PTY requested")
}
log.Printf("Using TERM=%s width=%d height=%d", sshPty.Term, sshPty.Window.Width, sshPty.Window.Height)
cpty, tty, err := pty.Open()
if err != nil {
return err
}
defer tty.Close()
state, err := terminal.GetState(int(cpty.Fd()))
if err != nil {
return err
}
defer terminal.Restore(int(cpty.Fd()), state)
colour.Fprintln(tty, "^BWelcome!^R")
go io.Copy(cpty, s)
go io.Copy(s, cpty)
parser, err := buildShellParser(tty)
if err != nil {
return err
}
rl, err := readline.NewEx(&readline.Config{
Prompt: "> ",
Stderr: tty,
Stdout: tty,
Stdin: tty,
FuncOnWidthChanged: func(f func()) {},
FuncMakeRaw: func() error {
_, err := terminal.MakeRaw(int(cpty.Fd())) // nolint: govet
return err
},
FuncExitRaw: func() error { return nil },
})
if err != nil {
return err
}
log.Printf("Loop")
for {
tty.Sync()
var line string
line, err = rl.Readline()
if err != nil {
if err == io.EOF {
return nil
}
return err
}
var args []string
args, err := shlex.Split(string(line))
if err != nil {
parser.Errorf("%s", err)
continue
}
var ctx *kong.Context
ctx, err = parser.Parse(args)
if err != nil {
parser.Errorf("%s", err)
if err, ok := err.(*kong.ParseError); ok {
log.Println(err.Error())
err.Context.PrintUsage(false)
}
continue
}
err = ctx.Run(ctx)
if err != nil {
parser.Errorf("%s", err)
continue
}
}
}
func buildShellParser(tty *os.File) (*kong.Kong, error) {
parser, err := kong.New(&grammar{},
kong.Name(""),
kong.Description("Example using Kong for interactive command parsing."),
kong.Writers(tty, tty),
kong.Exit(func(int) {}),
kong.ConfigureHelp(kong.HelpOptions{
NoAppSummary: true,
}),
kong.NoDefaultHelp(),
)
return parser, err
}
func handlerWithError(handle func(log *log.Logger, s ssh.Session) error) ssh.Handler {
return func(s ssh.Session) {
prefix := fmt.Sprintf("%s->%s ", s.LocalAddr(), s.RemoteAddr())
l := log.New(os.Stdout, prefix, log.LstdFlags)
err := handle(l, s)
if err != nil {
log.Printf("error: %s", err)
s.Exit(1)
} else {
log.Printf("Bye")
s.Exit(0)
}
}
}
var cli struct {
HostKey string `type:"existingfile" help:"SSH host key to use." default:"./_examples/server/server_rsa_key"`
Bind string `help:"Bind address for server." default:"127.0.0.1:6740"`
}
func main() {
ctx := kong.Parse(&cli,
kong.Name("server"),
kong.Description("A network server using Kong for interacting with clients."))
ssh.Handle(handlerWithError(handle))
log.Printf("SSH listening on: %s", cli.Bind)
log.Printf("Using host key: %s", cli.HostKey)
log.Println()
parts := strings.Split(cli.Bind, ":")
log.Printf("Connect with: ssh -p %s %s", parts[1], parts[0])
log.Println()
err := ssh.ListenAndServe(cli.Bind, nil, ssh.HostKeyFile(cli.HostKey))
ctx.FatalIfErrorf(err)
}
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAxK1QbPQYibc0VFZdc6GHPka5oTeGnXsMZiyX4JbHUJl1oNDB
Xg9NATbft+q/6ZDjyVEQhq8xgLvYFkL8qBLt/6UAaOub0RtmPqQwmxoNLWuXFFwn
YlBKApQ4gf58/jOcGPpdEwfjkjwLb536Bni25XMU4cYrdIvQIhtMaK+Zqja/3MAC
V6ZRZZCd8hABJqaZu+3mRElnF1d7gfMvA/hhaq7Y5VYr8rUrBHHimrT/GEP6aCbf
Npo43SfRnUDu2+EAK7vA9cM8fg/O/mvNR1/9jzOWyr8ZDLD6R6iaZCQ2anEPcqim
MCOtibSeVOms07Zcn/TSsgmfGwa8rQkpXVJA5wIDAQABAoIBAQCTUccGdajTrzkx
WyfQ71NgoJV3XyIkYAEfn5N8FTTi+LAVb4kILanemP3mw55RE8isCV65pA0OgqYP
tsmOE+/WKAAwlxs1/LIPhekqpM7uEMMv6v9NMxrc562UIc36kyn/w7loAebCqNtg
FhMsOcu1/wfLPidau0eB5LTNTYtq5RuSKxoindvatk+Zmk0KjoA+f25MlwCEHQNr