Skip to content
This repository has been archived by the owner on Sep 26, 2021. It is now read-only.

Commit

Permalink
Allow custom format for ls
Browse files Browse the repository at this point in the history
Signed-off-by: David Gageot <david@gageot.net>
  • Loading branch information
dgageot committed Dec 28, 2015
1 parent c64af29 commit adc6071
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 19 deletions.
10 changes: 7 additions & 3 deletions commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ var Commands = []cli.Command{
Action: fatalOnError(cmdKill),
},
{
Name: "ls",
Usage: "List machines",
Action: fatalOnError(cmdLs),
Flags: []cli.Flag{
cli.BoolFlag{
Name: "quiet, q",
Expand All @@ -229,10 +232,11 @@ var Commands = []cli.Command{
Usage: fmt.Sprintf("Timeout in seconds, default to %s", stateTimeoutDuration),
Value: lsDefaultTimeout,
},
cli.StringFlag{
Name: "format, f",
Usage: "Pretty-print machines using a Go template",
},
},
Name: "ls",
Usage: "List machines",
Action: fatalOnError(cmdLs),
},
{
Name: "regenerate-certs",
Expand Down
92 changes: 80 additions & 12 deletions commands/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"text/template"
"time"

"io"

"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/engine"
Expand All @@ -23,11 +25,14 @@ import (
"github.com/skarademir/naturalsort"
)

const lsDefaultTimeout = 10
const (
lsDefaultTimeout = 10
tableFormatKey = "table"
lsDefaultFormat = "table {{ .Name }}\t{{ .Active }}\t{{ .DriverName}}\t{{ .State }}\t{{ .URL }}\t{{ .Swarm }}\t{{ .DockerVersion }}\t{{ .Error}}"
)

var (
stateTimeoutDuration = lsDefaultTimeout * time.Second
defaultLsTemplate = "{{ .Name }}\t{{ .Active }}\t{{ .DriverName}}\t{{ .State }}\t{{ .URL }}\t{{ .Swarm }}\t{{ .DockerVersion }}\t{{ .Error}}"
)

// FilterOptions -
Expand All @@ -54,11 +59,25 @@ type HostListItem struct {
DockerVersion string
}

type Headers struct {
Name string
Active string
ActiveHost string
ActiveSwarm string
DriverName string
State string
URL string
SwarmOptions string
Swarm string
EngineOptions string
Error string
DockerVersion string
}

func cmdLs(c CommandLine, api libmachine.API) error {
stateTimeoutDuration = time.Duration(c.Int("timeout")) * time.Second
log.Debugf("ls timeout set to %s", stateTimeoutDuration)

quiet := c.Bool("quiet")
filters, err := parseFilters(c.StringSlice("filter"))
if err != nil {
return err
Expand All @@ -72,26 +91,51 @@ func cmdLs(c CommandLine, api libmachine.API) error {
hostList = filterHosts(hostList, filters)

// Just print out the names if we're being quiet
if quiet {
if c.Bool("quiet") {
for _, host := range hostList {
fmt.Println(host.Name)
}
return nil
}

t := template.New("lsConfig")
template, err := t.Parse(defaultLsTemplate + "\n")
template, table, err := parseFormat(c.String("format"))
if err != nil {
return err
}

swarmMasters := make(map[string]string)
swarmInfo := make(map[string]string)
var w io.Writer
if table {
tabWriter := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
defer tabWriter.Flush()

w = tabWriter

headers := &Headers{
Name: "NAME",
Active: "ACTIVE",
ActiveHost: "DRIVER",
ActiveSwarm: "STATE",
DriverName: "URL",
State: "STATE",
URL: "URL",
SwarmOptions: "SWARM_OPTIONS",
Swarm: "SWARM",
EngineOptions: "ENGINE_OPTIONS",
Error: "ERRORS",
DockerVersion: "DOCKER",
}

if err := template.Execute(w, headers); err != nil {
return err
}
} else {
w = os.Stdout
}

w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
defer w.Flush()
items := getHostListItems(hostList, hostInError)

fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM\tDOCKER\tERRORS")
swarmMasters := make(map[string]string)
swarmInfo := make(map[string]string)

for _, host := range hostList {
if host.HostOptions != nil {
Expand All @@ -106,7 +150,6 @@ func cmdLs(c CommandLine, api libmachine.API) error {
}
}

items := getHostListItems(hostList, hostInError)
for _, item := range items {
swarmColumn := ""
if item.SwarmOptions != nil && item.SwarmOptions.Discovery != "" {
Expand All @@ -125,6 +168,31 @@ func cmdLs(c CommandLine, api libmachine.API) error {
return nil
}

func parseFormat(format string) (*template.Template, bool, error) {
table := false
finalFormat := format

if finalFormat == "" {
finalFormat = lsDefaultFormat
}

if strings.HasPrefix(finalFormat, tableFormatKey) {
table = true
finalFormat = finalFormat[len(tableFormatKey):]
}

finalFormat = strings.Trim(finalFormat, " ")
r := strings.NewReplacer(`\t`, "\t", `\n`, "\n")
finalFormat = r.Replace(finalFormat)

template, err := template.New("").Parse(finalFormat + "\n")
if err != nil {
return nil, false, err
}

return template, table, nil
}

func parseFilters(filters []string) (FilterOptions, error) {
options := FilterOptions{}
for _, f := range filters {
Expand Down
2 changes: 1 addition & 1 deletion contrib/completion/bash/docker-machine.bash
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ _docker_machine_ls() {
COMPREPLY=()
;;
*)
COMPREPLY=($(compgen -W "--quiet --filter --timeout --help" -- "${cur}"))
COMPREPLY=($(compgen -W "--quiet --filter --format --timeout --help" -- "${cur}"))
;;
esac
}
Expand Down
43 changes: 40 additions & 3 deletions docs/reference/ls.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ parent="smn_machine_subcmds"

Options:

--quiet, -q Enable quiet mode
--filter [--filter option --filter option] Filter output based on conditions provided
--timeout, -t Timeout in seconds, default to 10s
--quiet, -q Enable quiet mode
--filter [--filter option --filter option] Filter output based on conditions provided
--timeout, -t Timeout in seconds, default to 10s
--format, -f Pretty-print machines using a Go template

## Timeout

Expand Down Expand Up @@ -47,6 +48,42 @@ The currently supported filters are:
- name (Machine name returned by driver, supports [golang style](https://github.com/google/re2/wiki/Syntax) regular expressions)
- label (Machine created with `--engine-label` option, can be filtered with `label=<key>[=<value>]`)

## Formatting

The formatting option (`--format`) will pretty-print machines using a Go template.

Valid placeholders for the Go template are listed below:

| Placeholder | Description |
| -------------- | ---------------------------------------- |
| .Name | Machine name |
| .Active | Is the machine active? |
| .ActiveHost | Is the machine an active non-swarm host? |
| .ActiveSwarm | Is the machine an active swarm master? |
| .DriverName | Driver name |
| .State | Machine state (running, stopped...) |
| .URL | Machine URL |
| .Swarm | Machine swarm name |
| .Error | Machine errors |
| .DockerVersion | Docker Daemon version |

When using the `--format` option, the `ls` command will either output the data exactly as the template declares or,
when using the table directive, will include column headers as well.

The following example uses a template without headers and outputs the `Name` and `Driver` entries separated by a colon
for all running machines:

$ docker-machine ls --format "{{.Name}}: {{.DriverName}}"
default: virtualbox
ec2: amazonec2

To list all machine names with their driver in a table format you can use:

$ docker-machine ls --format "table {{.Name}}: {{.DriverName}}"
NAME DRIVER
default virtualbox
ec2 amazonec2

## Examples

$ docker-machine ls
Expand Down
24 changes: 24 additions & 0 deletions test/integration/cli/ls.bats
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,27 @@ bootstrap_swarm () {
[[ ${lines[1]} == "testswarm2" ]]
[[ ${lines[2]} == "testswarm3" ]]
}

@test "ls: format on driver 'machine ls --format '{{ .DriverName }}'" {
run machine ls --format '{{ .DriverName }}'
[ "$status" -eq 0 ]
[[ ${#lines[@]} == 5 ]]
[[ ${lines[0]} =~ "none" ]]
[[ ${lines[1]} =~ "none" ]]
[[ ${lines[2]} =~ "none" ]]
[[ ${lines[3]} =~ "none" ]]
[[ ${lines[4]} =~ "none" ]]
}


@test "ls: format on name and driver 'machine ls --format 'table {{ .Name}}: {{ .DriverName }}'" {
run machine ls --format 'table {{ .Name}}: {{ .DriverName }}'
[ "$status" -eq 0 ]
[[ ${#lines[@]} == 6 ]]
[[ ${lines[1]} =~ "testmachine: none" ]]
[[ ${lines[2]} =~ "testmachine2: none" ]]
[[ ${lines[3]} =~ "testmachine3: none" ]]
[[ ${lines[4]} =~ "testmachine4: none" ]]
[[ ${lines[5]} =~ "testmachine5: none" ]]
}

0 comments on commit adc6071

Please sign in to comment.