✨ Allow jsonpath when print json or yaml

This commit is contained in:
OpenWaygate committed 2025-07-01 23:39:30 +08:00
1 parent 4292aeb9f1
commit dacc3219f4
6 files changed
+137 -37

No files matched your search

+1
View File
@@ -19,6 +19,7 @@ use_repo(
go_deps,
"com_github_jedib0t_go_pretty_v6",
"com_github_mark3labs_mcp_go",
"com_github_ohler55_ojg",
"com_github_savioxavier_termlink",
"com_github_spf13_cobra",
"com_github_spf13_pflag",
+2 -1
View File
@@ -3,7 +3,7 @@ module github.com/eat-pray-ai/yutu
go 1.24.3
require (
github.com/mark3labs/mcp-go v0.32.0
github.com/mark3labs/mcp-go v0.32.1-0.20250628092910-1eddde7bd69b
github.com/savioxavier/termlink v1.4.3
github.com/spf13/cobra v1.9.1
github.com/spf13/viper v1.20.1
@@ -40,6 +40,7 @@ require (
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jedib0t/go-pretty/v6 v6.6.7
github.com/ohler55/ojg v1.26.8
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/sagikazarmark/locafero v0.9.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
+6 -20
View File
@@ -18,8 +18,6 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
@@ -42,10 +40,12 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mark3labs/mcp-go v0.32.0 h1:fgwmbfL2gbd67obg57OfV2Dnrhs1HtSdlY/i5fn7MU8=
github.com/mark3labs/mcp-go v0.32.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
github.com/mark3labs/mcp-go v0.32.1-0.20250628092910-1eddde7bd69b h1:nxi80AOhzZBM8ZiP9PAP26MJOT6WbEpkut8fmcOFPuo=
github.com/mark3labs/mcp-go v0.32.1-0.20250628092910-1eddde7bd69b/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/ohler55/ojg v1.26.8 h1:njM65m+ej8sLHiFZIhJK9UkwOmDPsUikjGbTgcwu8CU=
github.com/ohler55/ojg v1.26.8/go.mod h1:/Y5dGWkekv9ocnUixuETqiL58f+5pAsUfg5P8e7Pa2o=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -58,8 +58,6 @@ github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWN
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k=
github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
github.com/savioxavier/termlink v1.4.2 h1:PRlvcStluuSKA87KCIqzODknYeQ3XEcgJP6DvAAVl1c=
github.com/savioxavier/termlink v1.4.2/go.mod h1:5T5ePUlWbxCHIwyF8/Ez1qufOoGM89RCg9NvG+3G3gc=
github.com/savioxavier/termlink v1.4.3 h1:Gh6vrG7jSn21cRiYdQqFXYcdXfM+Fg14aG487JTfKpA=
github.com/savioxavier/termlink v1.4.3/go.mod h1:5T5ePUlWbxCHIwyF8/Ez1qufOoGM89RCg9NvG+3G3gc=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
@@ -82,26 +80,16 @@ github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zI
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -118,8 +106,6 @@ golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
google.golang.org/api v0.238.0 h1:+EldkglWIg/pWjkq97sd+XxH7PxakNYoe/rkSTbnvOs=
google.golang.org/api v0.238.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/api v0.239.0 h1:2hZKUnFZEy81eugPs4e2XzIJ5SOwQg0G82bpXD65Puo=
google.golang.org/api v0.239.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
+1
View File
@@ -6,6 +6,7 @@ go_library(
importpath = "github.com/eat-pray-ai/yutu/pkg/utils",
visibility = ["//visibility:public"],
deps = [
"@com_github_ohler55_ojg//jp",
"@com_github_spf13_pflag//:pflag",
"@in_gopkg_yaml_v3//:yaml_v3",
],
+15 -7
View File
@@ -5,9 +5,9 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/ohler55/ojg/jp"
"github.com/spf13/pflag"
"io"
"os"
"os/exec"
"path/filepath"
"runtime"
@@ -15,17 +15,25 @@ import (
"gopkg.in/yaml.v3"
)
func PrintJSON(data interface{}, writer io.Writer) {
if writer == nil { // todo: remove fallback to stdout
writer = os.Stdout
func PrintJSON(data interface{}, jpath string, writer io.Writer) {
j, err := jp.ParseString(jpath)
if err != nil && jpath != "" {
_, _ = fmt.Fprintln(writer, "Invalid JSONPath:", jpath)
return
} else if jpath != "" {
data = j.Get(data)
}
marshalled, _ := json.MarshalIndent(data, "", " ")
_, _ = fmt.Fprintln(writer, string(marshalled))
}
func PrintYAML(data interface{}, writer io.Writer) {
if writer == nil { // todo: remove fallback to stdout
writer = os.Stdout
func PrintYAML(data interface{}, jpath string, writer io.Writer) {
j, err := jp.ParseString(jpath)
if err != nil && jpath != "" {
_, _ = fmt.Fprintln(writer, "Invalid JSONPath:", jpath)
return
} else if jpath != "" {
data = j.Get(data)
}
marshalled, _ := yaml.Marshal(data)
_, _ = fmt.Fprintln(writer, string(marshalled))
+112 -9
View File
@@ -2,7 +2,6 @@ package utils
import (
"bytes"
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"reflect"
@@ -115,24 +114,76 @@ func TestIsJson(t *testing.T) {
func TestPrintJSON(t *testing.T) {
type args struct {
data interface{}
data interface{}
jpath string
}
tests := []struct {
name string
args args
wantWriter string
}{
{
name: "empty jsonpath",
args: args{data: map[string]string{"key": "value"}, jpath: ""},
wantWriter: "{\n \"key\": \"value\"\n}\n",
},
{
name: "simple json",
args: args{data: map[string]string{"key": "value"}},
wantWriter: fmt.Sprint("{\n \"key\": \"value\"\n}\n"),
args: args{data: map[string]string{"key": "value"}, jpath: "$"},
wantWriter: "[\n {\n \"key\": \"value\"\n }\n]\n",
},
{
name: "invalid jsonpath",
args: args{
data: map[string]string{"key": "value"}, jpath: "//",
},
wantWriter: "Invalid JSONPath: //\n",
},
{
name: "extract specific field",
args: args{
data: map[string]interface{}{
"key": "value",
"another": "field",
}, jpath: "$.key",
},
wantWriter: "[\n \"value\"\n]\n",
},
{
name: "nested jsonpath",
args: args{
data: map[string]interface{}{
"item1": map[string]string{"key1": "value1"},
"item2": map[string]string{"key2": "value2"},
"count": 2,
},
jpath: "$.*.key1",
},
wantWriter: "[\n \"value1\"\n]\n",
},
{
name: "array jsonpath",
args: args{
data: []map[string]string{
{"key1": "value1"},
{"key2": "value2"},
{"key1": "value3"},
},
jpath: "$[*].key1",
},
wantWriter: "[\n \"value1\",\n \"value3\"\n]\n",
},
{
name: "nil data",
args: args{data: nil, jpath: "$"},
wantWriter: "[\n null\n]\n",
},
}
for _, tt := range tests {
t.Run(
tt.name, func(t *testing.T) {
writer := &bytes.Buffer{}
PrintJSON(tt.args.data, writer)
PrintJSON(tt.args.data, tt.args.jpath, writer)
if gotWriter := writer.String(); gotWriter != tt.wantWriter {
t.Errorf("PrintJSON() = %v, want %v", gotWriter, tt.wantWriter)
}
@@ -143,7 +194,8 @@ func TestPrintJSON(t *testing.T) {
func TestPrintYAML(t *testing.T) {
type args struct {
data interface{}
data interface{}
jpath string
}
tests := []struct {
name string
@@ -151,16 +203,67 @@ func TestPrintYAML(t *testing.T) {
wantWriter string
}{
{
name: "simple yaml",
args: args{data: map[string]string{"key": "value"}},
name: "empty jsonpath",
args: args{data: map[string]string{"key": "value"}, jpath: ""},
wantWriter: "key: value\n\n",
},
{
name: "simple yaml",
args: args{data: map[string]string{"key": "value"}, jpath: "$"},
wantWriter: "- key: value\n\n",
},
{
name: "invalid jsonpath",
args: args{
data: map[string]string{"key": "value"}, jpath: "//",
},
wantWriter: "Invalid JSONPath: //\n",
},
{
name: "extract specific field",
args: args{
data: map[string]interface{}{
"key": "value",
"another": "field",
}, jpath: "$.key",
},
wantWriter: "- value\n\n",
},
{
name: "nested jsonpath",
args: args{
data: map[string]interface{}{
"item1": map[string]string{"key1": "value1"},
"item2": map[string]string{"key2": "value2"},
"count": 2,
},
jpath: "$.*.key1",
},
wantWriter: "- value1\n\n",
},
{
name: "array jsonpath",
args: args{
data: []map[string]string{
{"key1": "value1"},
{"key2": "value2"},
{"key1": "value3"},
},
jpath: "$[*].key1",
},
wantWriter: "- value1\n- value3\n\n",
},
{
name: "nil data",
args: args{data: nil, jpath: "$"},
wantWriter: "- null\n\n",
},
}
for _, tt := range tests {
t.Run(
tt.name, func(t *testing.T) {
writer := &bytes.Buffer{}
PrintYAML(tt.args.data, writer)
PrintYAML(tt.args.data, tt.args.jpath, writer)
if gotWriter := writer.String(); gotWriter != tt.wantWriter {
t.Errorf("PrintYAML() = %v, want %v", gotWriter, tt.wantWriter)
}