Skip to content

Commit be33b91

Browse files
authored
refactor: switch node commands from index to name-based selection with interactive picker (#88)
1 parent 90f8485 commit be33b91

5 files changed

Lines changed: 414 additions & 404 deletions

File tree

cmd/dvb/logs.go

Lines changed: 19 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,17 @@ func newNodeLogsCmd() *cobra.Command {
7171
opts := &logsOptions{}
7272

7373
cmd := &cobra.Command{
74-
Use: "logs [devnet] [index]",
74+
Use: "logs [devnet] [node-name]",
7575
Short: "View logs from a node",
7676
Long: `View logs from a node in a devnet.
7777
7878
With context set (dvb use <devnet>):
79-
dvb node logs - Interactive picker to select node
80-
dvb node logs <index> - Show logs from a specific node
79+
dvb node logs - Interactive picker to select node
80+
dvb node logs <node-name> - Show logs from a specific node
8181
8282
Without context or explicit devnet:
83-
dvb node logs <devnet> <index> - Show logs from a specific node
84-
dvb node logs <devnet> - Show merged logs from all nodes
83+
dvb node logs <devnet> <node-name> - Show logs from a specific node
84+
dvb node logs <devnet> - Show merged logs from all nodes
8585
8686
In daemon mode, streams logs from the daemon.
8787
In standalone mode, reads log files from the data directory.
@@ -91,12 +91,12 @@ Examples:
9191
dvb use my-devnet
9292
dvb node logs
9393
94-
# Set context and view logs from node 0
94+
# Set context and view logs from a specific node
9595
dvb use my-devnet
96-
dvb node logs 0
96+
dvb node logs validator-0
9797
9898
# Show logs from a specific node (explicit devnet)
99-
dvb node logs my-devnet 0
99+
dvb node logs my-devnet validator-0
100100
101101
# Follow logs in real-time
102102
dvb node logs -f
@@ -113,14 +113,13 @@ Examples:
113113
if len(args) == 0 {
114114
// No args - requires context and will use picker
115115
if currentContext == nil {
116-
return fmt.Errorf("no devnet specified. Either:\n - Provide devnet: dvb node logs <devnet> [index]\n - Set context: dvb use <devnet>")
116+
return fmt.Errorf("no devnet specified. Either:\n - Provide devnet: dvb node logs <devnet> [node-name]\n - Set context: dvb use <devnet>")
117117
}
118118
// nodeArg stays empty, will be picked later
119119
} else if len(args) == 1 {
120-
// Determine if single arg is a node identifier or devnet name.
121-
// Node identifiers are: numeric (0, 1, 2) or "validator-N" pattern
122-
if looksLikeNodeIdentifier(args[0]) {
123-
// Treat as node - requires context
120+
// Determine if single arg is a node name or devnet name.
121+
if isNodeName(args[0]) {
122+
// Treat as node name - requires context
124123
if currentContext == nil {
125124
return fmt.Errorf("no devnet specified. Either:\n - Provide devnet: dvb node logs <devnet> %s\n - Set context: dvb use <devnet>", args[0])
126125
}
@@ -141,11 +140,11 @@ Examples:
141140

142141
// If context is set and no node specified, use picker
143142
if currentContext != nil && nodeArg == "" && daemonClient != nil {
144-
index, err := dvbcontext.PickNode(daemonClient, ns, devnetName)
143+
sel, err := dvbcontext.PickNode(cmd.Context(), daemonClient, ns, devnetName)
145144
if err != nil {
146145
return fmt.Errorf("failed to pick node: %w", err)
147146
}
148-
nodeArg = fmt.Sprintf("%d", index)
147+
nodeArg = sel.Name
149148
}
150149

151150
printContextHeader(explicitDevnet, currentContext)
@@ -176,12 +175,12 @@ func runLogs(ctx context.Context, opts *logsOptions) error {
176175
}
177176

178177
// Try daemon streaming if available and a specific node is requested
179-
if daemonClient != nil && !standalone && opts.node != "" {
180-
index, err := parseNodeIndex(opts.node)
181-
if err == nil {
182-
return streamLogsFromDaemon(ctx, opts, index)
178+
if daemonClient != nil && !standalone && opts.node != "" && isNodeName(opts.node) {
179+
sel, err := dvbcontext.ResolveNodeName(ctx, daemonClient, "", opts.devnet, opts.node)
180+
if err != nil {
181+
return err
183182
}
184-
// If we can't parse the index, fall through to file-based
183+
return streamLogsFromDaemon(ctx, opts, sel.Index)
185184
}
186185

187186
// Fall back to file-based logs (standalone mode or multi-node)
@@ -484,20 +483,6 @@ func tailLines(file *os.File, n int) ([]string, error) {
484483
return lines, nil
485484
}
486485

487-
// looksLikeNodeIdentifier returns true if the string looks like a node identifier.
488-
// Node identifiers are: pure numeric (0, 1, 2) or "validator-N" / "node-N" patterns.
489-
func looksLikeNodeIdentifier(s string) bool {
490-
// Pure numeric
491-
if _, err := parseNodeIndex(s); err == nil {
492-
return true
493-
}
494-
// Common node name patterns
495-
if strings.HasPrefix(s, "validator-") || strings.HasPrefix(s, "node-") || strings.HasPrefix(s, "full-") {
496-
return true
497-
}
498-
return false
499-
}
500-
501486
// streamLogsFromDaemon streams logs from the daemon for a specific node.
502487
func streamLogsFromDaemon(ctx context.Context, opts *logsOptions, index int) error {
503488
nodeColor := getNodeColor(opts.node)

0 commit comments

Comments
 (0)