Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --input-stream option. #7

Merged
merged 8 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading