networks.go RawHistoryFolder

1package cli
2
3import (
4	"context"
5	"fmt"
6	"io"
7	"strings"
8
9	"github.com/bnema/gordon/internal/adapters/in/cli/ui/components"
10	"github.com/bnema/gordon/internal/domain"
11	"github.com/spf13/cobra"
12)
13
14func newNetworksCmd() *cobra.Command {
15	var jsonOut bool
16
17	cmd := &cobra.Command{
18		Use:   "networks",
19		Short: "List Gordon-managed networks",
20		Long: `Display Docker networks managed by Gordon, including which containers
21are connected to each network.
22
23Examples:
24  gordon daemon networks
25  gordon daemon networks --json
26  gordon daemon networks --remote prod`,
27		RunE: func(cmd *cobra.Command, _ []string) error {
28			ctx := cmd.Context()
29			handle, err := resolveControlPlane(cliConfigPath)
30			if err != nil {
31				return err
32			}
33			defer handle.close()
34			return runNetworksList(ctx, handle.plane, cmd.OutOrStdout(), jsonOut)
35		},
36	}
37
38	cmd.Flags().BoolVar(&jsonOut, "json", false, "Output as JSON")
39
40	return cmd
41}
42
43func runNetworksList(ctx context.Context, cp ControlPlane, out io.Writer, jsonOut bool) error {
44	networks, err := cp.ListNetworks(ctx)
45	if err != nil {
46		return fmt.Errorf("failed to list networks: %w", err)
47	}
48
49	if jsonOut {
50		result := make([]map[string]any, 0, len(networks))
51		for _, net := range networks {
52			if net == nil {
53				continue
54			}
55			result = append(result, map[string]any{
56				"name":       net.Name,
57				"driver":     net.Driver,
58				"containers": net.Containers,
59			})
60		}
61		return writeJSON(out, result)
62	}
63
64	if len(networks) == 0 {
65		return cliWriteLine(out, cliRenderMuted("No Gordon-managed networks found"))
66	}
67
68	if err := cliWriteLine(out, cliRenderTitle("Networks")); err != nil {
69		return err
70	}
71
72	return renderNetworksTable(out, networks)
73}
74
75func renderNetworksTable(out io.Writer, networks []*domain.NetworkInfo) error {
76	rows := make([][]string, 0, len(networks))
77	for _, net := range networks {
78		if net == nil {
79			continue
80		}
81		containers := strings.Join(net.Containers, ", ")
82		if containers == "" {
83			containers = "-"
84		}
85		if len(containers) > 40 {
86			containers = containers[:37] + "..."
87		}
88		rows = append(rows, []string{
89			net.Name,
90			net.Driver,
91			fmt.Sprintf("%d", len(net.Containers)),
92			containers,
93		})
94	}
95
96	table := components.NewTable(
97		components.WithColumns([]components.TableColumn{
98			{Title: "Name", Width: 25},
99			{Title: "Driver", Width: 10},
100			{Title: "Containers", Width: 12},
101			{Title: "Connected", Width: 40},
102		}),
103		components.WithRows(rows),
104	)
105
106	return cliWriteLine(out, table.View())
107}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close