Skip to content

Commit

Permalink
Add --input-stream option. (#7)
Browse files Browse the repository at this point in the history
Co-authored-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>

* add clientMethodParam
* add -i (--input-stream) flag to bind io.Reader in Input struct.
* inject length field
  • Loading branch information
fujiwara authored May 20, 2024
1 parent 2c1feef commit 40945ae
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 58 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
# vendor/

.envrc
*.log
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,11 @@ Arguments:
[<input>] input JSON
Flags:
-h, --help Show context-sensitive help.
-c, --compact compact JSON output
-q, --query=STRING JMESPath query to apply to output
-h, --help Show context-sensitive help.
-i, --input-stream=STRING bind input filename or '-' to io.Reader field in the input struct
-c, --compact compact JSON output
-q, --query=STRING JMESPath query to apply to output
-v, --version show version
```

- `service`: AWS service name.
Expand Down Expand Up @@ -119,6 +121,22 @@ If the method name is "kebab-case", it automatically converts to "PascalCase" (f
$ aws-sdk-client-go ecs describe-clusters '{"Cluster":"default"}'
```

#### `--input-stream` option

`--input-stream` option allows you to bind a file or stdin to the input struct.

```console
$ aws-sdk-client-go s3 put-object '{"Bucket": "my-bucket", "Key": "my.txt"}' --input-stream my.txt
```

[s3#PutObjectInput](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#PutObjectInput) has `Body` field of `io.Reader`. `--input-stream` option binds the file to the field.

When the input struct has only one field of `io.Reader`, `aws-sdk-client-go` reads the file and binds it to the field automatically. (At now, all SDK input structs have only one field of `io.Reader`.)

When the input struct has a "\*Length" field for the size of the content, `aws-sdk-client-go` sets the size of the content to the field automatically. For example, [s3#PutObjectInput](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3#PutObjectInput) has `ContentLength` field.

If `--input-stream` is "-", `aws-sdk-client-go` reads from stdin. In this case, `aws-sdk-client-go` reads all contents into memory, so it is not suitable for large files. Consider using a file for large content.

#### Query output by JMESPath

`--query` option allows you to query the output by JMESPath like the AWS CLI.
Expand Down
13 changes: 6 additions & 7 deletions cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,25 @@ import (
"testing"

"github.com/alecthomas/kong"
"github.com/aws/aws-sdk-go-v2/aws"
sdkclient "github.com/fujiwara/aws-sdk-client-go"
)

func init() {
sdkclient.SetClientMethod("foo#Client.List", func(_ context.Context, _ aws.Config, _ json.RawMessage) (any, error) {
sdkclient.SetClientMethod("foo#Client.List", func(_ context.Context, _ *sdkclient.ClientMethodParam) (any, error) {
return []string{"a", "b", "c"}, nil
})
sdkclient.SetClientMethod("foo#Client.Get", func(_ context.Context, _ aws.Config, _ json.RawMessage) (any, error) {
sdkclient.SetClientMethod("foo#Client.Get", func(_ context.Context, _ *sdkclient.ClientMethodParam) (any, error) {
return struct{ Name string }{Name: "foo"}, nil
})
sdkclient.SetClientMethod("bar#Client.List", func(_ context.Context, _ aws.Config, _ json.RawMessage) (any, error) {
sdkclient.SetClientMethod("bar#Client.List", func(_ context.Context, _ *sdkclient.ClientMethodParam) (any, error) {
return []string{"x", "y", "z"}, nil
})
sdkclient.SetClientMethod("bar#Client.Get", func(_ context.Context, _ aws.Config, _ json.RawMessage) (any, error) {
sdkclient.SetClientMethod("bar#Client.Get", func(_ context.Context, _ *sdkclient.ClientMethodParam) (any, error) {
return struct{ Name string }{Name: "bar"}, nil
})
sdkclient.SetClientMethod("baz#Client.Echo", func(_ context.Context, _ aws.Config, b json.RawMessage) (any, error) {
sdkclient.SetClientMethod("baz#Client.Echo", func(_ context.Context, p *sdkclient.ClientMethodParam) (any, error) {
var v any
err := json.Unmarshal(b, &v)
err := json.Unmarshal(p.InputBytes, &v)
return v, err
})
}
Expand Down
60 changes: 54 additions & 6 deletions cmd/aws-sdk-client-gen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,27 @@ import (
"encoding/json"
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/{{ .PkgName }}"
)
{{ range .Methods }}
func {{ $.PkgName }}_{{ .Name }}(ctx context.Context, awsCfg aws.Config, b json.RawMessage) (any, error) {
svc := {{ $.PkgName }}.NewFromConfig(awsCfg)
func {{ $.PkgName }}_{{ .Name }}(ctx context.Context, p *clientMethodParam) (any, error) {
svc := {{ $.PkgName }}.NewFromConfig(p.awsCfg)
var in {{ .Input }}
if err := json.Unmarshal(b, &in); err != nil {
{{ if .InputReaderLengthField }}
p.mustInject("{{ .InputReaderLengthField }}", p.InputReaderLength)
{{ end }}
if err := json.Unmarshal(p.InputBytes, &in); err != nil {
return nil, fmt.Errorf("failed to unmarshal request: %w", err)
}
if p.InputReader != nil {
{{- if .InputReaderField }}
in.{{ .InputReaderField }} = p.InputReader
{{- else }}
return nil, fmt.Errorf("{{ $.PkgName }}.{{ .Name }}Input has no io.Reader field")
{{- end }}
}
return svc.{{ .Name }}(ctx, &in)
}
Expand Down Expand Up @@ -65,10 +75,48 @@ func gen(pkgName string, clientType reflect.Type, genNames []string) error {
log.Printf("no params func %s", method.Name)
continue
}
inputParam := method.Type.In(2)
var inputReaderField, inputReaderLengthField string
for j := 0; j < inputParam.Elem().NumField(); j++ {
field := inputParam.Elem().Field(j)
if t := field.Type.String(); t == "io.Reader" {
log.Printf("found %s field in %s.%sInput %s %s", t, pkgName, method.Name, field.Name, t)
if inputReaderField != "" {
return fmt.Errorf("found multiple io.Reader fields in %s.%sInput", pkgName, method.Name)
}
inputReaderField = field.Name
}
}
if inputReaderField != "" {
for j := 0; j < inputParam.Elem().NumField(); j++ {
field := inputParam.Elem().Field(j)
if t := field.Name; strings.Contains(t, "Length") {
log.Printf("found %s field in %s.%sInput %s %s", t, pkgName, method.Name, field.Name, t)
if inputReaderLengthField != "" {
return fmt.Errorf("found multiple Length fields in %s.%sInput", pkgName, method.Name)
}
inputReaderLengthField = field.Name
}
}
}
methods = append(methods, map[string]string{
"Name": method.Name,
"Input": strings.TrimPrefix(params[2], "*"),
"Name": method.Name,
"Input": strings.TrimPrefix(params[2], "*"),
"InputReaderField": inputReaderField,
"InputReaderLengthField": inputReaderLengthField,
})
/*
output := method.Type.Out(0)
if output.Kind() == reflect.Ptr {
output = output.Elem()
}
for j := 0; j < output.NumField(); j++ {
field := output.Field(j)
if t := field.Type.String(); strings.Contains(t, "io.") {
log.Printf("found %s field in %s.%sOutput %s %s", t, pkgName, method.Name, field.Name, t)
}
}
*/
}

tmpl, err := template.New("clientGen").Parse(templateStr)
Expand Down
2 changes: 2 additions & 0 deletions export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ func SetClientMethod(key string, fn ClientMethod) {
func ClientMethods() map[string]ClientMethod {
return clientMethods
}

type ClientMethodParam = clientMethodParam
15 changes: 15 additions & 0 deletions gen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,18 @@ services:
- ListDeliveryStreams
kinesis:
# all methods of the service
lambda:
s3:
- GetBucketLocation
- GetObject
- ListBuckets
- ListObjects
- ListObjectsV2
- HeadObject
- PutObject
- PutObjectAcl
- PutObjectTagging
- RestoreObject
- SelectObjectContent
- UploadPart
- UploadPartCopy
26 changes: 14 additions & 12 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,29 @@ go 1.21.0

require (
github.com/alecthomas/kong v0.9.0
github.com/aws/aws-sdk-go-v2 v1.26.1
github.com/aws/aws-sdk-go-v2/config v1.27.11
github.com/aws/aws-sdk-go-v2 v1.27.0
github.com/aws/aws-sdk-go-v2/config v1.27.14
github.com/goccy/go-yaml v1.11.3
github.com/itchyny/gojq v0.12.15
github.com/jmespath/go-jmespath v0.4.0
)

require (
github.com/aws/aws-sdk-go-v2/credentials v1.17.11 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.14 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.8 // indirect
github.com/aws/smithy-go v1.20.2 // indirect
github.com/fatih/color v1.10.0 // indirect
github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
golang.org/x/sys v0.6.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
)
50 changes: 28 additions & 22 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,30 @@ github.com/alecthomas/kong v0.9.0 h1:G5diXxc85KvoV2f0ZRVuMsi45IrBgx9zDNGNj165aPA
github.com/alecthomas/kong v0.9.0/go.mod h1:Y47y5gKfHp1hDc7CH7OeXgLIpp+Q2m1Ni0L5s3bI8Os=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA=
github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2/config v1.27.11 h1:f47rANd2LQEYHda2ddSCKYId18/8BhSRM4BULGmfgNA=
github.com/aws/aws-sdk-go-v2/config v1.27.11/go.mod h1:SMsV78RIOYdve1vf36z8LmnszlRWkwMQtomCAI0/mIE=
github.com/aws/aws-sdk-go-v2/credentials v1.17.11 h1:YuIB1dJNf1Re822rriUOTxopaHHvIq0l/pX3fwO+Tzs=
github.com/aws/aws-sdk-go-v2/credentials v1.17.11/go.mod h1:AQtFPsDH9bI2O+71anW6EKL+NcD7LG3dpKGMV4SShgo=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc=
github.com/aws/aws-sdk-go-v2 v1.27.0 h1:7bZWKoXhzI+mMR/HjdMx8ZCC5+6fY0lS5tr0bbgiLlo=
github.com/aws/aws-sdk-go-v2 v1.27.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2/config v1.27.14 h1:QOg8Ud53rrmdjBHX080AaYUBhG2ER28kP/yjE7afF/0=
github.com/aws/aws-sdk-go-v2/config v1.27.14/go.mod h1:CLgU27opbIwnjwH++zQPvF4qsEIqviKL6l8b1AtRImc=
github.com/aws/aws-sdk-go-v2/credentials v1.17.14 h1:0y1IAEldTO2ZA3Lcq7u7y4Q2tUQlB3At2LZQijUHu3U=
github.com/aws/aws-sdk-go-v2/credentials v1.17.14/go.mod h1:En2zXCfDZJgtbp2UnzHDgKMz+mSRc4pA3Ka+jxoJvaA=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.2 h1:HTAQSEibYaSioHzjOQssUJnE8itwVP9SzmdR6lqC38g=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.2/go.mod h1:NjUtmUEIimOc5tPw//xqKNK/spUqCTSbxjwzCrnsj8U=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 h1:lf/8VTF2cM+N4SLzaYJERKEWAXq8MOMpZfU6wEPWsPk=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7/go.mod h1:4SjkU7QiqK2M9oozyMzfZ/23LmUY+h3oFqhdeP5OMiI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 h1:4OYVp0705xu8yjdyoWix0r9wPIRXnIzzOoUpQVHIJ/g=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7/go.mod h1:vd7ESTEvI76T2Na050gODNmNU7+OyKrIKroYTu4ABiI=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/gxJBcSWDMZlgyFUM962F51A5CRhDLbxLdmo=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 h1:vN8hEbpRnL7+Hopy9dzmRle1xmDc7o8tmY0klsr175w=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 h1:Jux+gDDyi1Lruk+KHF91tK2KCuY61kzoCpvtvJJBtOE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 h1:cwIxeBttqPN3qkaAjcEcsh8NYr8n2HZPkcKgPAi1phU=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 h1:Wx0rlZoEJR7JwlSZcHnEa7CNjrSIyVxMFWGAaXy4fJY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9/go.mod h1:aVMHdE0aHO3v+f/iw01fmXV/5DbfQ3Bi9nN7nd9bE9Y=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.7 h1:sdPpNCoUijc0ntu024ZdjrXh3mB9rud5SjmE7djIfK4=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.7/go.mod h1:8RMeDMFTkkDQ5LvaaAykdkNVVR0eQxGWm8CD6uBvd1M=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.1 h1:/vljM1ZswUEIRHWVxEqDhLzOSGmDcstW2zeTt23Ipf0=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.1/go.mod h1:XhJksmKh1RYjMbWHf3ZwQF0UYJjlqrm45NVvDe54SOU=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.8 h1:FCYhQETaff4Skb2Hz9WoUqJAesr4MIQ9+TQ9ypjz7Ic=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.8/go.mod h1:s+7oFIwiOegfrF00xNowWwLAtRiA9xhvm1UpZdJ0aus=
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
Expand All @@ -46,6 +46,10 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/itchyny/gojq v0.12.15 h1:WC1Nxbx4Ifw5U2oQWACYz32JK8G9qxNtHzrvW4KEcqI=
github.com/itchyny/gojq v0.12.15/go.mod h1:uWAHCbCIla1jiNxmeT5/B5mOjSdfkCq6p8vxWg+BM10=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
Expand All @@ -54,17 +58,19 @@ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
57 changes: 49 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ var Version = "HEAD"

var clientMethods = make(map[string]ClientMethod)

type ClientMethod func(context.Context, aws.Config, json.RawMessage) (any, error)
type ClientMethod func(context.Context, *clientMethodParam) (any, error)

type CLI struct {
Service string `arg:"" help:"service name" default:""`
Method string `arg:"" help:"method name" default:""`
Input string `arg:"" help:"input JSON" default:"{}"`
Compact bool `short:"c" help:"compact JSON output"`
Query string `short:"q" help:"JMESPath query to apply to output"`
Version bool `short:"v" help:"show version"`

InputStream string `short:"i" help:"bind input filename or '-' to io.Reader field in the input struct"`
Compact bool `short:"c" help:"compact JSON output"`
Query string `short:"q" help:"JMESPath query to apply to output"`
Version bool `short:"v" help:"show version"`

w io.Writer
}
Expand Down Expand Up @@ -65,17 +67,17 @@ func (c *CLI) CallMethod(ctx context.Context) error {
fmt.Fprintf(c.w, "See https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/%s\n", key)
return nil
}

fn := clientMethods[key]
if fn == nil {
return fmt.Errorf("unknown function %s", key)
}

awsCfg, err := config.LoadDefaultConfig(ctx)
p, err := c.clientMethodParam(ctx)
if err != nil {
return err
}
out, err := fn(ctx, awsCfg, json.RawMessage(c.Input))
defer p.Cleanup()

out, err := fn(ctx, p)
if err != nil {
return err
}
Expand All @@ -102,6 +104,45 @@ func (c *CLI) CallMethod(ctx context.Context) error {
return nil
}

func (c *CLI) clientMethodParam(ctx context.Context) (*clientMethodParam, error) {
awsCfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
return nil, err
}
p := &clientMethodParam{
awsCfg: awsCfg,
InputBytes: json.RawMessage(c.Input),
InputReader: nil,
}

switch c.InputStream {
case "":
// do nothing
case "-": // stdin
buf := &bytes.Buffer{}
if _, err := io.Copy(buf, os.Stdin); err != nil {
if err != io.EOF {
return nil, fmt.Errorf("failed to read from stdin: %w", err)
}
}
p.InputReader = buf
p.InputReaderLength = aws.Int64(int64(buf.Len()))
default:
f, err := os.Open(c.InputStream)
if err != nil {
return nil, fmt.Errorf("failed to open input file: %w", err)
}
p.InputReader = f
p.cleanup = append(p.cleanup, f.Close)
st, err := f.Stat()
if err != nil {
return nil, fmt.Errorf("failed to stat input file: %w", err)
}
p.InputReaderLength = aws.Int64(st.Size())
}
return p, nil
}

func (c *CLI) ListMethods(_ context.Context) error {
methods := make([]string, 0)
for name := range clientMethods {
Expand Down
Loading

0 comments on commit 40945ae

Please sign in to comment.