✨ Allow jsonpath when print json or yaml
This commit is contained in:
1 parent
4292aeb9f1
commit
dacc3219f4
6 files changed
+137
-37
No files matched your search
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user