diff --git a/src/cmd/list.go b/src/cmd/list.go index 7188701b7..57a995845 100644 --- a/src/cmd/list.go +++ b/src/cmd/list.go @@ -17,17 +17,36 @@ package cmd import ( + "encoding/json" "errors" "fmt" "os" "text/tabwriter" + "time" "github.com/containers/toolbox/pkg/podman" "github.com/containers/toolbox/pkg/utils" + "github.com/docker/go-units" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) +type toolboxImage struct { + ID string + Names []string + Created interface{} +} + +type toolboxContainer struct { + ID string + Name string + Names []string + Status string + State string + Created interface{} + Image string +} + var ( listFlags struct { onlyContainers bool @@ -82,8 +101,8 @@ func list(cmd *cobra.Command, args []string) error { lsImages = false } - var images []map[string]interface{} - var containers []map[string]interface{} + var images []toolboxImage + var containers []toolboxContainer var err error if lsImages { @@ -104,7 +123,7 @@ func list(cmd *cobra.Command, args []string) error { return nil } -func listContainers() ([]map[string]interface{}, error) { +func listContainers() ([]toolboxContainer, error) { logrus.Debug("Fetching containers with label=com.redhat.component=fedora-toolbox") args := []string{"--all", "--filter", "label=com.redhat.component=fedora-toolbox"} containers_old, err := podman.GetContainers(args...) @@ -128,7 +147,24 @@ func listContainers() ([]map[string]interface{}, error) { containers = utils.SortJSON(containers, "Names", false) } - return containers, nil + var toolboxContainers []toolboxContainer + for _, container := range containers { + var c toolboxContainer + containerJSON, err := json.Marshal(container) + if err != nil { + logrus.Errorf("failed to marshal container: %v", err) + continue + } + + err = json.Unmarshal(containerJSON, &c) + if err != nil { + logrus.Errorf("failed to unmarshal container: %v", err) + continue + } + toolboxContainers = append(toolboxContainers, c) + } + + return toolboxContainers, nil } func listHelp(cmd *cobra.Command, args []string) { @@ -152,7 +188,7 @@ func listHelp(cmd *cobra.Command, args []string) { } } -func listImages() ([]map[string]interface{}, error) { +func listImages() ([]toolboxImage, error) { logrus.Debug("Fetching images with label=com.redhat.component=fedora-toolbox") args := []string{"--filter", "label=com.redhat.component=fedora-toolbox"} images_old, err := podman.GetImages(args...) @@ -179,33 +215,37 @@ func listImages() ([]map[string]interface{}, error) { images = utils.SortJSON(images, "names", true) } - return images, nil + var toolboxImages []toolboxImage + for _, image := range images { + var i toolboxImage + imageJSON, err := json.Marshal(image) + if err != nil { + logrus.Errorf("failed to marshal toolbox image: %v", err) + continue + } + + err = json.Unmarshal(imageJSON, &i) + if err != nil { + logrus.Errorf("failed to unmarshal toolbox image: %v", err) + continue + } + toolboxImages = append(toolboxImages, i) + } + + return toolboxImages, nil } -func listOutput(images, containers []map[string]interface{}) { +func listOutput(images []toolboxImage, containers []toolboxContainer) { if len(images) != 0 { writer := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) fmt.Fprintf(writer, "%s\t%s\t%s\n", "IMAGE ID", "IMAGE NAME", "CREATED") - var idKey, nameKey, createdKey string - if podman.CheckVersion("2.0.0") { - idKey = "Id" - nameKey = "Names" - createdKey = "Created" - } else if podman.CheckVersion("1.8.3") { - idKey = "ID" - nameKey = "Names" - createdKey = "Created" - } else { - idKey = "id" - nameKey = "names" - createdKey = "created" - } - for _, image := range images { - id := utils.ShortID(image[idKey].(string)) - name := image[nameKey].([]interface{})[0].(string) - created := image[createdKey].(string) + var id, name, created string + id = utils.ShortID(image.ID) + name = image.Names[0] + created = image.GetCreatedString() + fmt.Fprintf(writer, "%s\t%s\t%s\n", id, name, created) } @@ -226,35 +266,65 @@ func listOutput(images, containers []map[string]interface{}) { "STATUS", "IMAGE NAME") - var idKey, createdKey, statusKey string - if podman.CheckVersion("2.0.0") { - idKey = "Id" - createdKey = "CreatedAt" - statusKey = "State" - } else { - idKey = "ID" - createdKey = "Created" - statusKey = "Status" + for _, container := range containers { + var id, name, created, status, imageName string + id = utils.ShortID(container.ID) + name = container.GetName() + status = container.GetStatus() + created = container.GetCreatedString() + imageName = container.Image + + fmt.Fprintf(writer, "%s\t%s\t%s\t%s\t%s\n", id, name, created, status, imageName) } - for _, container := range containers { - id := utils.ShortID(container[idKey].(string)) + writer.Flush() + } +} - var nameString string - switch name := container["Names"].(type) { - case string: - nameString = name - case []interface{}: - nameString = name[0].(string) - } +// GetCreatedString returns a string with human-readable time when an image was +// created +func (i toolboxImage) GetCreatedString() string { + var created string + switch value := i.Created.(type) { + case string: + created = value + case float64: + created = units.HumanDuration(time.Since(time.Unix(int64(value), 0))) + " ago" + } + return created +} - created := container[createdKey].(string) - status := container[statusKey].(string) - imageName := container["Image"].(string) +// GetName returns the first name of a container +func (c toolboxContainer) GetName() string { + var name string + if c.Name != "" { + name = c.Name + } else { + name = c.Names[0] + } + return name +} - fmt.Fprintf(writer, "%s\t%s\t%s\t%s\t%s\n", id, nameString, created, status, imageName) - } +// GetStatus returns the status of a container +func (c toolboxContainer) GetStatus() string { + var status string + if c.Status != "" { + status = c.Status + } else { + status = c.State + } + return status +} - writer.Flush() +// GetCreatedString returns a string with human-readable time when a container +// was created +func (c toolboxContainer) GetCreatedString() string { + var created string + switch value := c.Created.(type) { + case string: + created = value + case float64: + created = units.HumanDuration(time.Since(time.Unix(int64(value), 0))) + " ago" } + return created } diff --git a/src/cmd/run.go b/src/cmd/run.go index 7a1364665..1530001d5 100644 --- a/src/cmd/run.go +++ b/src/cmd/run.go @@ -194,7 +194,7 @@ func runCommand(container string, } else if containersCount == 1 && defaultContainer { fmt.Fprintf(os.Stderr, "Error: container %s not found\n", container) - container = containers[0]["Names"].(string) + container = containers[0].GetName() fmt.Fprintf(os.Stderr, "Entering container %s instead.\n", container) fmt.Fprintf(os.Stderr, "Use the 'create' command to create a different toolbox.\n") fmt.Fprintf(os.Stderr, "Run '%s --help' for usage.\n", executableBase)