Skip to content

Commit

Permalink
Make list-* commands consistent
Browse files Browse the repository at this point in the history
This change ensures that all list-* commands show the same style response when there are no
values to display.  It is a simple print to stderr that says 'No foos to display.'
This fixes https://bugs.launchpad.net/juju/+bug/1596687
  • Loading branch information
natefinch committed Sep 22, 2016
1 parent f10fe4a commit 1a887db
Show file tree
Hide file tree
Showing 26 changed files with 92 additions and 72 deletions.
9 changes: 4 additions & 5 deletions cmd/juju/action/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ func (c *listCommand) Run(ctx *cmd.Context) error {
case "yaml", "json":
output = shortOutput
default:
if len(sortedNames) == 0 {
ctx.Infof("No actions defined for %s.", c.applicationTag.Id())
return nil
}
var list []listOutput
for _, name := range sortedNames {
list = append(list, listOutput{name, shortOutput[name]})
Expand All @@ -140,11 +144,6 @@ func (c *listCommand) printTabular(writer io.Writer, value interface{}) error {
return errors.New("unexpected value")
}

if len(list) == 0 {
fmt.Fprintf(writer, "No actions defined for %s", c.applicationTag.Id())
return nil
}

tw := output.TabWriter(writer)
fmt.Fprintf(tw, "%s\t%s\n", "ACTION", "DESCRIPTION")
for _, value := range list {
Expand Down
5 changes: 3 additions & 2 deletions cmd/juju/action/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package action_test
import (
"bytes"
"errors"
"fmt"
"strings"

"github.com/juju/cmd"
Expand Down Expand Up @@ -122,7 +123,7 @@ snapshot Take a snapshot of the database.
should: "work properly when no results found",
withArgs: []string{validServiceId},
expectNoResults: true,
expectMessage: "No actions defined for " + validServiceId,
expectMessage: fmt.Sprintf("No actions defined for %s.\n", validServiceId),
}}

for i, t := range tests {
Expand All @@ -149,7 +150,7 @@ snapshot Take a snapshot of the database.
if t.expectFullSchema {
checkFullSchema(c, t.withCharmActions, result)
} else if t.expectNoResults {
c.Check(string(result), gc.Matches, t.expectMessage+"(?sm).*")
c.Check(testing.Stderr(ctx), gc.Matches, t.expectMessage)
} else {
c.Check(testing.Stdout(ctx), gc.Equals, simpleOutput)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/juju/backups/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (c *listCommand) Run(ctx *cmd.Context) error {
}

if len(result.List) == 0 {
fmt.Fprintln(ctx.Stdout, "(no backups found)")
ctx.Infof("No backups to display.")
return nil
}

Expand Down
10 changes: 10 additions & 0 deletions cmd/juju/block/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ func (c *listCommand) Run(ctx *cmd.Context) (err error) {
return c.listForModel(ctx)
}

const noBlocks = "No commands are currently disabled."

func (c *listCommand) listForModel(ctx *cmd.Context) (err error) {
api, err := c.apiFunc(c)
if err != nil {
Expand All @@ -96,6 +98,10 @@ func (c *listCommand) listForModel(ctx *cmd.Context) (err error) {
if err != nil {
return errors.Trace(err)
}
if len(result) == 0 {
ctx.Infof(noBlocks)
return nil
}
return c.out.Write(ctx, formatBlockInfo(result))
}

Expand All @@ -110,6 +116,10 @@ func (c *listCommand) listForController(ctx *cmd.Context) (err error) {
if err != nil {
return errors.Trace(err)
}
if len(result) == 0 {
ctx.Infof(noBlocks)
return nil
}
info, err := FormatModelBlockInfo(result)
if err != nil {
return errors.Trace(err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/juju/block/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (s *listCommandSuite) TestInit(c *gc.C) {
func (s *listCommandSuite) TestListEmpty(c *gc.C) {
ctx, err := testing.RunCommand(c, block.NewListCommandForTest(&mockListClient{}, nil))
c.Assert(err, jc.ErrorIsNil)
c.Assert(testing.Stdout(ctx), gc.Equals, "No commands are currently disabled.\n")
c.Assert(testing.Stderr(ctx), gc.Equals, "No commands are currently disabled.\n")
}

func (s *listCommandSuite) TestListError(c *gc.C) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/juju/cachedimages/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (c *listCommand) Run(ctx *cmd.Context) (err error) {
}
imageInfo := c.imageMetadataToImageInfo(results)
if len(imageInfo) == 0 {
fmt.Fprintf(ctx.Stdout, "no matching images found\n")
ctx.Infof("No images to display.")
return nil
}
fmt.Fprintf(ctx.Stdout, "Cached images:\n")
Expand Down
2 changes: 1 addition & 1 deletion cmd/juju/cachedimages/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func runListCommand(c *gc.C, args ...string) (*cmd.Context, error) {
func (*listImagesCommandSuite) TestListImagesNone(c *gc.C) {
context, err := runListCommand(c, "--kind", "kvm")
c.Assert(err, jc.ErrorIsNil)
c.Assert(testing.Stdout(context), gc.Equals, "no matching images found\n")
c.Assert(testing.Stderr(context), gc.Equals, "No images to display.\n")
}

func (*listImagesCommandSuite) TestListImagesFormatJson(c *gc.C) {
Expand Down
4 changes: 4 additions & 0 deletions cmd/juju/commands/list_sshkeys.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ func (c *listKeysCommand) Run(context *cmd.Context) error {
if result.Error != nil {
return result.Error
}
if len(result.Result) == 0 {
context.Infof("No keys to display.")
return nil
}
fmt.Fprintf(context.Stdout, "Keys used in model: %s\n", c.ConnectionName())
fmt.Fprintln(context.Stdout, strings.Join(result.Result, "\n"))
return nil
Expand Down
5 changes: 3 additions & 2 deletions cmd/juju/romulus/listagreements/listagreements.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ func (c *listAgreementsCommand) Run(ctx *cmd.Context) error {
if err != nil {
return errors.Annotate(err, "failed to list user agreements")
}
if agreements == nil {
agreements = []wireformat.AgreementResponse{}
if len(agreements) == 0 {
ctx.Infof("No agreements to display.")
return nil
}
err = c.out.Write(ctx, agreements)
if err != nil {
Expand Down
10 changes: 3 additions & 7 deletions cmd/juju/romulus/listagreements/listagreements_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ const (
func (s *listAgreementsSuite) TestGetUsersAgreements(c *gc.C) {
ctx, err := cmdtesting.RunCommand(c, listagreements.NewListAgreementsCommand())
c.Assert(err, jc.ErrorIsNil)
c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "[]\n")
c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "")
c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "No agreements to display.\n")
c.Assert(s.client.called, jc.IsTrue)

s.client.setError("well, this is embarassing")
Expand Down Expand Up @@ -91,13 +92,8 @@ func (s *listAgreementsSuite) TestGetUsersAgreements(c *gc.C) {
}

func (s *listAgreementsSuite) TestGetUsersAgreementsWithTermOwner(c *gc.C) {
ctx, err := cmdtesting.RunCommand(c, listagreements.NewListAgreementsCommand())
c.Assert(err, jc.ErrorIsNil)
c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "[]\n")
c.Assert(s.client.called, jc.IsTrue)

s.client.setError("well, this is embarassing")
ctx, err = cmdtesting.RunCommand(c, listagreements.NewListAgreementsCommand())
ctx, err := cmdtesting.RunCommand(c, listagreements.NewListAgreementsCommand())
c.Assert(err, gc.ErrorMatches, "failed to list user agreements: well, this is embarassing")
c.Assert(s.client.called, jc.IsTrue)

Expand Down
5 changes: 5 additions & 0 deletions cmd/juju/romulus/listplans/list_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@ func (c *ListPlansCommand) Run(ctx *cmd.Context) (rErr error) {
}
output[i] = outputPlan
}

if len(output) == 0 && c.out.Name() == "tabular" {
ctx.Infof("No plans to display.")
}

err = c.out.Write(ctx, output)
if err != nil {
return errors.Trace(err)
Expand Down
14 changes: 2 additions & 12 deletions cmd/juju/storage/filesystemlistformatters.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,11 @@ import (
"strings"

"github.com/dustin/go-humanize"
"github.com/juju/errors"
"github.com/juju/juju/cmd/output"
)

// formatFilesystemListTabular writes a tabular summary of filesystem instances.
func formatFilesystemListTabular(writer io.Writer, value interface{}) error {
infos, ok := value.(map[string]FilesystemInfo)
if !ok {
return errors.Errorf("expected value of type %T, got %T", infos, value)
}
formatFilesystemListTabularTyped(writer, infos)
return nil
}

func formatFilesystemListTabularTyped(writer io.Writer, infos map[string]FilesystemInfo) {
func formatFilesystemListTabular(writer io.Writer, infos map[string]FilesystemInfo) error {
tw := output.TabWriter(writer)

print := func(values ...string) {
Expand Down Expand Up @@ -76,7 +66,7 @@ func formatFilesystemListTabularTyped(writer io.Writer, infos map[string]Filesys
)
}

tw.Flush()
return tw.Flush()
}

type filesystemAttachmentInfo struct {
Expand Down
6 changes: 3 additions & 3 deletions cmd/juju/storage/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ func (c *listCommand) Run(ctx *cmd.Context) (err error) {
if err != nil {
return err
}
if output == nil {
if output == nil && c.out.Name() == "tabular" {
ctx.Infof("No storage to display.")
return nil
}
return c.out.Write(ctx, output)
Expand Down Expand Up @@ -123,8 +124,7 @@ func (c *listCommand) generateListOutput(ctx *cmd.Context, api StorageListAPI) (
}

func formatListTabular(writer io.Writer, value interface{}) error {

switch value.(type) {
switch value := value.(type) {
case map[string]StorageInfo:
return formatStorageListTabular(writer, value)

Expand Down
8 changes: 1 addition & 7 deletions cmd/juju/storage/listformatters.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,11 @@ import (
"strconv"
"strings"

"github.com/juju/errors"
"github.com/juju/juju/cmd/output"
)

// formatListTabular writes a tabular summary of storage instances.
func formatStorageListTabular(writer io.Writer, value interface{}) error {
storageInfo, ok := value.(map[string]StorageInfo)
if !ok {
return errors.Errorf("expected value of type %T, got %T", storageInfo, value)
}

func formatStorageListTabular(writer io.Writer, storageInfo map[string]StorageInfo) error {
tw := output.TabWriter(writer)
p := func(values ...interface{}) {
for _, v := range values {
Expand Down
1 change: 1 addition & 0 deletions cmd/juju/storage/poollist.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ func (c *poolListCommand) Run(ctx *cmd.Context) (err error) {
return err
}
if len(result) == 0 {
ctx.Infof("No storage pools to display.")
return nil
}
output := formatPoolInfo(result)
Expand Down
15 changes: 2 additions & 13 deletions cmd/juju/storage/volumelistformatters.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,11 @@ import (
"strings"

"github.com/dustin/go-humanize"
"github.com/juju/errors"
"github.com/juju/juju/cmd/output"
)

// formatVolumeListTabular returns a tabular summary of volume instances.
func formatVolumeListTabular(writer io.Writer, value interface{}) error {
infos, ok := value.(map[string]VolumeInfo)
if !ok {
return errors.Errorf("expected value of type %T, got %T", infos, value)
}
formatVolumeListTabularTyped(writer, infos)
return nil
}

func formatVolumeListTabularTyped(writer io.Writer, infos map[string]VolumeInfo) {
func formatVolumeListTabular(writer io.Writer, infos map[string]VolumeInfo) error {
tw := output.TabWriter(writer)

print := func(values ...string) {
Expand Down Expand Up @@ -76,8 +66,7 @@ func formatVolumeListTabularTyped(writer io.Writer, infos map[string]VolumeInfo)
)
}

tw.Flush()
return
return tw.Flush()
}

type volumeAttachmentInfo struct {
Expand Down
4 changes: 2 additions & 2 deletions cmd/juju/subnet/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ func (c *listCommand) Run(ctx *cmd.Context) error {
// Display a nicer message in case no subnets were found.
if len(subnets) == 0 {
if c.SpaceName != "" || c.ZoneName != "" {
ctx.Infof("no subnets found matching requested criteria")
ctx.Infof("No subnets found matching requested criteria.")
} else {
ctx.Infof("no subnets to display")
ctx.Infof("No subnets to display.")
}
return nil
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/juju/subnet/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func (s *ListSuite) TestRunWhenNoneMatchSucceeds(c *gc.C) {
s.api.Subnets = s.api.Subnets[0:0]

s.AssertRunSucceeds(c,
`no subnets found matching requested criteria\n`,
`No subnets found matching requested criteria.\n`,
"", // empty stdout.
"--space", "default",
)
Expand All @@ -237,7 +237,7 @@ func (s *ListSuite) TestRunWhenNoSubnetsExistSucceeds(c *gc.C) {
s.api.Subnets = s.api.Subnets[0:0]

s.AssertRunSucceeds(c,
`no subnets to display\n`,
`No subnets to display.\n`,
"", // empty stdout.
)

Expand Down
9 changes: 9 additions & 0 deletions cmd/juju/user/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ func (c *listCommand) modelUsers(ctx *cmd.Context) error {
if err != nil {
return err
}
if len(result) == 0 {
ctx.Infof("No users to display.")
return nil
}
return c.out.Write(ctx, common.ModelUserInfoFromParams(result, c.clock.Now()))
}

Expand All @@ -148,6 +152,11 @@ func (c *listCommand) controllerUsers(ctx *cmd.Context) error {
return err
}

if len(result) == 0 {
ctx.Infof("No users to display.")
return nil
}

return c.out.Write(ctx, c.apiUsersToUserInfoSlice(result))
}

Expand Down
2 changes: 1 addition & 1 deletion featuretests/cmd_juju_subnet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func (s *cmdSubnetSuite) TestSubnetListNoResults(c *gc.C) {
context := s.Run(c, expectedSuccess, "list-subnets")
s.AssertOutput(c, context,
"", // no stdout output
"no subnets to display\n",
"No subnets to display.\n",
)
}

Expand Down
2 changes: 1 addition & 1 deletion featuretests/storage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ block:
func (s *cmdStorageSuite) TestListPoolsNameNoMatch(c *gc.C) {
stdout, stderr, err := runPoolList(c, "--name", "cranky")
c.Assert(err, jc.ErrorIsNil)
c.Assert(stderr, gc.Equals, "")
c.Assert(stderr, gc.Equals, "No storage pools to display.\n")
c.Assert(stdout, gc.Equals, "")
}

Expand Down
5 changes: 5 additions & 0 deletions payload/status/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ func (c *ListCommand) Run(ctx *cmd.Context) error {
fmt.Fprintf(ctx.Stderr, "%v\n", err)
}

if len(payloads) == 0 {
ctx.Infof("No payloads to display.")
return nil
}

// Note that we do not worry about c.CompatVersion for payloads...
formatter := newListFormatter(payloads)
formatted := formatter.format()
Expand Down
8 changes: 2 additions & 6 deletions payload/status/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,8 @@ func (s *listSuite) TestNoPayloads(c *gc.C) {
code, stdout, stderr := runList(c, command)
c.Assert(code, gc.Equals, 0)

c.Check(stdout, gc.Equals, `
[Unit Payloads]
UNIT MACHINE PAYLOAD-CLASS STATUS TYPE ID TAGS
`[1:])
c.Check(stderr, gc.Equals, "")
c.Check(stderr, gc.Equals, "No payloads to display.\n")
c.Check(stdout, gc.Equals, "")
}

func (s *listSuite) TestPatternsOkay(c *gc.C) {
Expand Down
6 changes: 6 additions & 0 deletions resource/cmd/list_charm_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ func (c *ListCharmResourcesCommand) Run(ctx *cmd.Context) error {
if len(resources) != 1 {
return errors.New("got bad data from charm store")
}
res := resources[0]

if len(res) == 0 && c.out.Name() == "tabular" {
ctx.Infof("No resources to display.")
return nil
}

// Note that we do not worry about c.CompatVersion
// for show-charm-resources...
Expand Down
Loading

0 comments on commit 1a887db

Please sign in to comment.