mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
refactor: tui package for CLI styles and prompts, restyle confirmation
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/docker/cli/cli/streams"
|
"github.com/docker/cli/cli/streams"
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/psviderski/uncloud/pkg/client"
|
"github.com/psviderski/uncloud/pkg/client"
|
||||||
@@ -135,7 +136,7 @@ func runDeploy(ctx context.Context, uncli *cli.CLI, opts deployOptions) error {
|
|||||||
fmt.Println(plan.Format(resolver))
|
fmt.Println(plan.Format(resolver))
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
confirmed, err := cli.Confirm()
|
confirmed, err := tui.Confirm("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("confirm deployment: %w", err)
|
return fmt.Errorf("confirm deployment: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/psviderski/uncloud/cmd/uncloud/caddy"
|
"github.com/psviderski/uncloud/cmd/uncloud/caddy"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
"github.com/psviderski/uncloud/internal/cli/config"
|
"github.com/psviderski/uncloud/internal/cli/config"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/network"
|
"github.com/psviderski/uncloud/internal/machine/network"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/psviderski/uncloud/pkg/client"
|
"github.com/psviderski/uncloud/pkg/client"
|
||||||
@@ -224,7 +225,7 @@ func add(ctx context.Context, uncli *cli.CLI, remoteMachine *cli.RemoteMachine,
|
|||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
if !opts.yes {
|
if !opts.yes {
|
||||||
confirmed, err := cli.Confirm()
|
confirmed, err := tui.Confirm("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("confirm deployment: %w", err)
|
return fmt.Errorf("confirm deployment: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -118,7 +119,7 @@ func remove(ctx context.Context, uncli *cli.CLI, nameOrID string, opts removeOpt
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !opts.yes {
|
if !opts.yes {
|
||||||
confirmed, err := cli.Confirm()
|
confirmed, err := tui.Confirm("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("confirm removal: %w", err)
|
return fmt.Errorf("confirm removal: %w", err)
|
||||||
}
|
}
|
||||||
@@ -154,7 +155,7 @@ func remove(ctx context.Context, uncli *cli.CLI, nameOrID string, opts removeOpt
|
|||||||
|
|
||||||
// Remove the connection to the machine from the uncloud config if it exists.
|
// Remove the connection to the machine from the uncloud config if it exists.
|
||||||
if uncli.Config != nil {
|
if uncli.Config != nil {
|
||||||
contextName := uncli.GetContextOverrideOrCurrent()
|
contextName := uncli.ContextOverrideOrCurrent()
|
||||||
if context, ok := uncli.Config.Contexts[contextName]; ok {
|
if context, ok := uncli.Config.Contexts[contextName]; ok {
|
||||||
for i, c := range context.Connections {
|
for i, c := range context.Connections {
|
||||||
if c.MachineID == m.Id {
|
if c.MachineID == m.Id {
|
||||||
|
|||||||
+2
-1
@@ -11,6 +11,7 @@ import (
|
|||||||
"charm.land/lipgloss/v2/table"
|
"charm.land/lipgloss/v2/table"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
@@ -231,7 +232,7 @@ func collectContainers(ctx context.Context, cli *client.Client) ([]containerInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if msc.Metadata != nil && msc.Metadata.Error != "" {
|
if msc.Metadata != nil && msc.Metadata.Error != "" {
|
||||||
client.PrintWarning(fmt.Sprintf("failed to list containers on machine %s: %s", machineName,
|
tui.PrintWarning(fmt.Sprintf("failed to list containers on machine %s: %s", machineName,
|
||||||
msc.Metadata.Error))
|
msc.Metadata.Error))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/cli/cli/streams"
|
"github.com/docker/cli/cli/streams"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@@ -83,7 +84,7 @@ If the service has multiple replicas and no container ID is specified, the comma
|
|||||||
|
|
||||||
func runExec(ctx context.Context, uncli *cli.CLI, serviceName string, command []string, opts execCliOptions) error {
|
func runExec(ctx context.Context, uncli *cli.CLI, serviceName string, command []string, opts execCliOptions) error {
|
||||||
// Disable TTY allocation if not connected to a terminal
|
// Disable TTY allocation if not connected to a terminal
|
||||||
if !cli.IsStdoutTerminal() {
|
if !tui.IsStdoutTerminal() {
|
||||||
opts.noTty = true
|
opts.noTty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
mapset "github.com/deckarep/golang-set/v2"
|
mapset "github.com/deckarep/golang-set/v2"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/psviderski/uncloud/pkg/client"
|
"github.com/psviderski/uncloud/pkg/client"
|
||||||
"github.com/psviderski/uncloud/pkg/client/compose"
|
"github.com/psviderski/uncloud/pkg/client/compose"
|
||||||
@@ -171,7 +172,7 @@ func runLogs(ctx context.Context, uncli *cli.CLI, serviceNames []string, opts lo
|
|||||||
serviceNames = foundServices
|
serviceNames = foundServices
|
||||||
|
|
||||||
for _, name := range notFoundServices {
|
for _, name := range notFoundServices {
|
||||||
client.PrintWarning(fmt.Sprintf("service '%s' not found in the cluster, skipping", name))
|
tui.PrintWarning(fmt.Sprintf("service '%s' not found in the cluster, skipping", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/psviderski/uncloud/internal/cli"
|
"github.com/psviderski/uncloud/internal/cli"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@@ -79,7 +80,7 @@ func remove(ctx context.Context, uncli *cli.CLI, names []string, opts removeOpti
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
confirmed, err := cli.Confirm()
|
confirmed, err := tui.Confirm("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("confirm removal: %w", err)
|
return fmt.Errorf("confirm removal: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -71,7 +71,7 @@ func (cli *CLI) SetCurrentContext(name string) error {
|
|||||||
return cli.Config.Save()
|
return cli.Config.Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *CLI) GetContextOverrideOrCurrent() string {
|
func (cli *CLI) ContextOverrideOrCurrent() string {
|
||||||
if cli.contextOverride != "" {
|
if cli.contextOverride != "" {
|
||||||
return cli.contextOverride
|
return cli.contextOverride
|
||||||
}
|
}
|
||||||
@@ -81,6 +81,14 @@ func (cli *CLI) GetContextOverrideOrCurrent() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DirectConnection returns the connection string if --connect or UNCLOUD_CONNECT was specified.
|
||||||
|
func (cli *CLI) DirectConnection() string {
|
||||||
|
if cli.conn != nil {
|
||||||
|
return cli.conn.String()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// ConnectCluster connects to a cluster using the context override or the current context if not specified.
|
// ConnectCluster connects to a cluster using the context override or the current context if not specified.
|
||||||
// If the CLI was initialised with a machine connection, the config is ignored and the connection is used instead.
|
// If the CLI was initialised with a machine connection, the config is ignored and the connection is used instead.
|
||||||
func (cli *CLI) ConnectCluster(ctx context.Context) (*client.Client, error) {
|
func (cli *CLI) ConnectCluster(ctx context.Context) (*client.Client, error) {
|
||||||
@@ -316,7 +324,7 @@ type AddMachineOptions struct {
|
|||||||
// cluster. The machine client is connected to the new machine and can be used to interact with it.
|
// cluster. The machine client is connected to the new machine and can be used to interact with it.
|
||||||
// Both client should be closed after use by the caller.
|
// Both client should be closed after use by the caller.
|
||||||
func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (*client.Client, *client.Client, error) {
|
func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (*client.Client, *client.Client, error) {
|
||||||
contextName := cli.GetContextOverrideOrCurrent()
|
contextName := cli.ContextOverrideOrCurrent()
|
||||||
c, err := cli.ConnectCluster(ctx)
|
c, err := cli.ConnectCluster(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("connect to cluster (context '%s'): %w", contextName, err)
|
return nil, nil, fmt.Errorf("connect to cluster (context '%s'): %w", contextName, err)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
tea "charm.land/bubbletea/v2"
|
tea "charm.land/bubbletea/v2"
|
||||||
"charm.land/lipgloss/v2"
|
"charm.land/lipgloss/v2"
|
||||||
"github.com/psviderski/uncloud/internal/cli/config"
|
"github.com/psviderski/uncloud/internal/cli/config"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/fs"
|
"github.com/psviderski/uncloud/internal/fs"
|
||||||
"github.com/psviderski/uncloud/pkg/client"
|
"github.com/psviderski/uncloud/pkg/client"
|
||||||
"github.com/psviderski/uncloud/pkg/client/connector"
|
"github.com/psviderski/uncloud/pkg/client/connector"
|
||||||
@@ -33,7 +34,7 @@ func ConnectCluster(ctx context.Context, conn config.MachineConnection, opts Con
|
|||||||
// If the stdout is not a terminal, it falls back to simple progress logs to stderr.
|
// If the stdout is not a terminal, it falls back to simple progress logs to stderr.
|
||||||
func connectClusterWithProgress(ctx context.Context, conn config.MachineConnection) (*client.Client, error) {
|
func connectClusterWithProgress(ctx context.Context, conn config.MachineConnection) (*client.Client, error) {
|
||||||
// If stdout is not a terminal, fall back to simple progress logs.
|
// If stdout is not a terminal, fall back to simple progress logs.
|
||||||
if !IsStdoutTerminal() {
|
if !tui.IsStdoutTerminal() {
|
||||||
fmt.Fprintln(os.Stderr, "Connecting to", conn.String())
|
fmt.Fprintln(os.Stderr, "Connecting to", conn.String())
|
||||||
cli, err := connectCluster(ctx, conn)
|
cli, err := connectCluster(ctx, conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"charm.land/huh/v2"
|
"charm.land/huh/v2"
|
||||||
"github.com/cenkalti/backoff/v4"
|
"github.com/cenkalti/backoff/v4"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
||||||
"github.com/psviderski/uncloud/internal/sshexec"
|
"github.com/psviderski/uncloud/internal/sshexec"
|
||||||
"google.golang.org/protobuf/types/known/emptypb"
|
"google.golang.org/protobuf/types/known/emptypb"
|
||||||
@@ -88,7 +89,7 @@ func provisionMachine(ctx context.Context, exec sshexec.Executor, version string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func promptResetMachine() error {
|
func promptResetMachine() error {
|
||||||
if !IsStdinTerminal() {
|
if !tui.IsStdinTerminal() {
|
||||||
return errors.New("the remote machine is already initialised as a cluster member; " +
|
return errors.New("the remote machine is already initialised as a cluster member; " +
|
||||||
"cannot ask to confirm reset in non-interactive mode, " +
|
"cannot ask to confirm reset in non-interactive mode, " +
|
||||||
"use --yes flag or set UNCLOUD_AUTO_CONFIRM=true to auto-confirm")
|
"use --yes flag or set UNCLOUD_AUTO_CONFIRM=true to auto-confirm")
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"charm.land/huh/v2"
|
|
||||||
"golang.org/x/term"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Confirm() (bool, error) {
|
|
||||||
var confirmed bool
|
|
||||||
form := huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewConfirm().
|
|
||||||
Title(
|
|
||||||
"Do you want to continue?",
|
|
||||||
).
|
|
||||||
Affirmative("Yes!").
|
|
||||||
Negative("No").
|
|
||||||
Value(&confirmed),
|
|
||||||
),
|
|
||||||
).WithAccessible(true)
|
|
||||||
if err := form.Run(); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return confirmed, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsStdinTerminal checks if the standard input is a terminal (TTY).
|
|
||||||
func IsStdinTerminal() bool {
|
|
||||||
return term.IsTerminal(int(os.Stdin.Fd()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsStdoutTerminal checks if the standard output is a terminal (TTY).
|
|
||||||
func IsStdoutTerminal() bool {
|
|
||||||
return term.IsTerminal(int(os.Stdout.Fd()))
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package tui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PrintWarning(msg string) {
|
||||||
|
styledMsg := BoldYellow.Render(fmt.Sprintf("WARNING: %s", msg))
|
||||||
|
fmt.Fprintln(os.Stderr, styledMsg)
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package tui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"charm.land/huh/v2"
|
||||||
|
"charm.land/lipgloss/v2"
|
||||||
|
"golang.org/x/term"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Confirm shows a confirmation prompt with a yellow-styled title.
|
||||||
|
// If title is empty, it defaults to "Do you want to continue?".
|
||||||
|
func Confirm(title string) (bool, error) {
|
||||||
|
if title == "" {
|
||||||
|
title = "Do you want to continue?"
|
||||||
|
}
|
||||||
|
|
||||||
|
var confirmed bool
|
||||||
|
form := huh.NewForm(
|
||||||
|
huh.NewGroup(
|
||||||
|
huh.NewConfirm().
|
||||||
|
Title(title).
|
||||||
|
Affirmative("Yes!").
|
||||||
|
Negative("No").
|
||||||
|
Value(&confirmed),
|
||||||
|
),
|
||||||
|
).WithTheme(ThemeConfirm()).
|
||||||
|
WithAccessible(true)
|
||||||
|
if err := form.Run(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return confirmed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ThemeConfirm returns a huh theme with a bold yellow title style for the confirmation prompt.
|
||||||
|
func ThemeConfirm() huh.Theme {
|
||||||
|
return huh.ThemeFunc(func(isDark bool) *huh.Styles {
|
||||||
|
t := huh.ThemeBase(isDark)
|
||||||
|
t.Focused.Title = t.Focused.Title.Foreground(lipgloss.Yellow).Bold(true)
|
||||||
|
return t
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsStdinTerminal checks if the standard input is a terminal (TTY).
|
||||||
|
func IsStdinTerminal() bool {
|
||||||
|
return term.IsTerminal(int(os.Stdin.Fd()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsStdoutTerminal checks if the standard output is a terminal (TTY).
|
||||||
|
func IsStdoutTerminal() bool {
|
||||||
|
return term.IsTerminal(int(os.Stdout.Fd()))
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package tui
|
||||||
|
|
||||||
|
import "charm.land/lipgloss/v2"
|
||||||
|
|
||||||
|
var (
|
||||||
|
Faint = lipgloss.NewStyle().Faint(true)
|
||||||
|
Red = lipgloss.NewStyle().Foreground(lipgloss.Red)
|
||||||
|
Green = lipgloss.NewStyle().Foreground(lipgloss.Green)
|
||||||
|
Yellow = lipgloss.NewStyle().Foreground(lipgloss.Yellow)
|
||||||
|
|
||||||
|
Bold = lipgloss.NewStyle().Bold(true)
|
||||||
|
BoldRed = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Red)
|
||||||
|
BoldGreen = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Green)
|
||||||
|
BoldYellow = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Yellow)
|
||||||
|
|
||||||
|
NameStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("152"))
|
||||||
|
)
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"charm.land/lipgloss/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func PrintWarning(msg string) {
|
|
||||||
style := lipgloss.NewStyle().Foreground(lipgloss.Color("11")) // Bright yellow.
|
|
||||||
styledMsg := style.Render(fmt.Sprintf("WARNING: %s", msg))
|
|
||||||
fmt.Fprintln(os.Stderr, styledMsg)
|
|
||||||
}
|
|
||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/containerd/errdefs"
|
"github.com/containerd/errdefs"
|
||||||
"github.com/docker/compose/v2/pkg/progress"
|
"github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/docker/docker/api/types/volume"
|
"github.com/docker/docker/api/types/volume"
|
||||||
|
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||||
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
"github.com/psviderski/uncloud/internal/machine/api/pb"
|
||||||
"github.com/psviderski/uncloud/pkg/api"
|
"github.com/psviderski/uncloud/pkg/api"
|
||||||
)
|
)
|
||||||
@@ -70,7 +71,7 @@ func (cli *Client) ListVolumes(ctx context.Context, filter *api.VolumeFilter) ([
|
|||||||
for _, mv := range machineVolumes {
|
for _, mv := range machineVolumes {
|
||||||
if mv.Metadata != nil && mv.Metadata.Error != "" {
|
if mv.Metadata != nil && mv.Metadata.Error != "" {
|
||||||
// TODO: return failed machines in the response.
|
// TODO: return failed machines in the response.
|
||||||
PrintWarning(fmt.Sprintf("failed to list volumes on machine '%s': %s",
|
tui.PrintWarning(fmt.Sprintf("failed to list volumes on machine '%s': %s",
|
||||||
mv.Metadata.Machine, mv.Metadata.Error))
|
mv.Metadata.Machine, mv.Metadata.Error))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user