node list and module list answer --json, and the nodes and modules verbs use it (hq ADR 0195)
The console's discovery reads the machines and the modules; parsing a printed column breaks when it is reworded. Both now answer JSON on --json, as status and seats do, and the seat verbs ask for it.
This commit is contained in:
@@ -147,6 +147,36 @@ func moduleCommand(ctx context.Context, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// **The same list, for something other than a person** (novox/hq ADR 0195): what each module
|
||||||
|
// is, where it runs, whether it is current, and what it says of itself.
|
||||||
|
if len(args) > 1 && args[1] == "--json" {
|
||||||
|
type listed struct {
|
||||||
|
Module string `json:"module"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Built string `json:"built,omitempty"`
|
||||||
|
Head string `json:"head,omitempty"`
|
||||||
|
Current bool `json:"current"`
|
||||||
|
Provided bool `json:"provided,omitempty"`
|
||||||
|
On []string `json:"on"`
|
||||||
|
Provides []string `json:"provides,omitempty"`
|
||||||
|
Requires []string `json:"requires,omitempty"`
|
||||||
|
Claims []string `json:"claims,omitempty"`
|
||||||
|
Capabilities []string `json:"capabilities,omitempty"`
|
||||||
|
}
|
||||||
|
out := make([]listed, 0, len(entries))
|
||||||
|
for _, e := range entries {
|
||||||
|
m := e.Manifest
|
||||||
|
l := listed{Module: m.Module, Version: m.Version, Built: e.Source.BuiltFrom, Head: e.Source.Head,
|
||||||
|
Current: e.Provided || e.Source.Repository == "" || e.Source.Current(), Provided: e.Provided,
|
||||||
|
On: append([]string{}, e.On...), Provides: m.Offers(), Requires: m.Requires,
|
||||||
|
Capabilities: m.Capabilities}
|
||||||
|
for _, c := range m.Claims {
|
||||||
|
l.Claims = append(l.Claims, c.At()+"/"+c.Name)
|
||||||
|
}
|
||||||
|
out = append(out, l)
|
||||||
|
}
|
||||||
|
return printJSON(out)
|
||||||
|
}
|
||||||
if len(entries) == 0 {
|
if len(entries) == 0 {
|
||||||
fmt.Println("this mesh knows about no modules yet")
|
fmt.Println("this mesh knows about no modules yet")
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -44,6 +45,21 @@ func nodeCommand(ctx context.Context, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// **The same list, for something other than a person** — the console's discovery reads it
|
||||||
|
// (novox/hq ADR 0195), and a reader that parses a printed column breaks when it is reworded.
|
||||||
|
if len(args) > 1 && args[1] == "--json" {
|
||||||
|
type listed struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Heard string `json:"heard"`
|
||||||
|
Mode string `json:"mode"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
out := make([]listed, 0, len(nodes))
|
||||||
|
for _, n := range nodes {
|
||||||
|
out = append(out, listed{Name: n.Name, Heard: heardFrom(n), Mode: modeOf(n), ID: n.ID})
|
||||||
|
}
|
||||||
|
return printJSON(out)
|
||||||
|
}
|
||||||
if len(nodes) == 0 {
|
if len(nodes) == 0 {
|
||||||
// Said rather than printed as nothing: an empty list and a failed read must never
|
// Said rather than printed as nothing: an empty list and a failed read must never
|
||||||
// look the same, and this command answering "none" is only honest because getting
|
// look the same, and this command answering "none" is only honest because getting
|
||||||
@@ -500,3 +516,13 @@ func orNotReported(s string) string {
|
|||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// printJSON prints a value as indented JSON, the shape every `--json` answers in.
|
||||||
|
func printJSON(v any) error {
|
||||||
|
body, err := json.MarshalIndent(v, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(string(body))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,14 +66,14 @@ func argvFor(verb string, args map[string]any) ([]string, error) {
|
|||||||
case "status":
|
case "status":
|
||||||
return []string{"status", "--json"}, nil
|
return []string{"status", "--json"}, nil
|
||||||
case "nodes":
|
case "nodes":
|
||||||
return []string{"node", "list"}, nil
|
return []string{"node", "list", "--json"}, nil
|
||||||
case "node":
|
case "node":
|
||||||
if err := need("node"); err != nil {
|
if err := need("node"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return []string{"node", "show", str("node")}, nil
|
return []string{"node", "show", str("node")}, nil
|
||||||
case "modules":
|
case "modules":
|
||||||
return []string{"module", "list"}, nil
|
return []string{"module", "list", "--json"}, nil
|
||||||
case "seats":
|
case "seats":
|
||||||
return []string{"seats", "--json"}, nil
|
return []string{"seats", "--json"}, nil
|
||||||
case "builds":
|
case "builds":
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -249,3 +250,17 @@ func TestARowAheadOfThisBuildIsServedAnyway(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// novox/hq ADR 0195: the console's discovery reads the machines and the modules; they answer as JSON,
|
||||||
|
// as status and seats do, so nothing parses a printed column.
|
||||||
|
func TestTheNodesAndModulesVerbsAnswerAsJSON(t *testing.T) {
|
||||||
|
for verb, want := range map[string]string{"nodes": "[node list --json]", "modules": "[module list --json]"} {
|
||||||
|
argv, err := argvFor(verb, map[string]any{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if fmt.Sprint(argv) != want {
|
||||||
|
t.Errorf("%s runs %v, want %s", verb, argv, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user