Skip to content

Commit 7b23192

Browse files
committed
Updated to add context
1 parent 0cdb85d commit 7b23192

File tree

14 files changed

+477
-100
lines changed

14 files changed

+477
-100
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,16 @@ You can create a payload with form data:
189189

190190
The payload should be a `struct` where the fields are converted to form tuples. File uploads require a field of type `multipart.File`.
191191

192+
## Unmarshalling responses
193+
194+
You can implement your own unmarshalling of responses by implementing the `Unmarshaler` interface:
195+
196+
```go
197+
type Unmarshaler interface {
198+
Unmarshal(mimetype string, r io.Reader) error
199+
}
200+
```
201+
192202
## Streaming Responses
193203

194204
If the returned content is a stream of JSON responses, then you can use the `OptResponse(fn func() error)` option, which

cmd/api/anthropic.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package main
22

33
import (
4+
"context"
45
"fmt"
56

7+
// Packages
68
"github.com/djthorpe/go-tablewriter"
79
"github.com/mutablelogic/go-client"
810
"github.com/mutablelogic/go-client/pkg/anthropic"
@@ -52,15 +54,17 @@ func anthropicParse(flags *Flags, opts ...client.ClientOpt) error {
5254
///////////////////////////////////////////////////////////////////////////////
5355
// METHODS
5456

55-
func anthropicChat(w *tablewriter.Writer, args []string) error {
57+
func anthropicChat(ctx context.Context, w *tablewriter.Writer, args []string) error {
5658
// Request -> Response
5759
message := schema.NewMessage("user")
5860
for _, arg := range args {
59-
message.Add(arg)
61+
message.Add(schema.Text(arg))
6062
}
6163

6264
// Request -> Response
63-
responses, err := anthropicClient.Messages([]*schema.Message{message})
65+
responses, err := anthropicClient.Messages(ctx, []*schema.Message{
66+
message,
67+
})
6468
if err != nil {
6569
return err
6670
}

cmd/api/bitwarden.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"context"
45
"fmt"
56
"os"
67
"path/filepath"
@@ -104,7 +105,7 @@ func bwParse(flags *Flags, opts ...client.ClientOpt) error {
104105
///////////////////////////////////////////////////////////////////////////////
105106
// API METHODS
106107

107-
func bwAuth(w *tablewriter.Writer, _ []string) error {
108+
func bwAuth(_ context.Context, w *tablewriter.Writer, _ []string) error {
108109
opts := []bitwarden.RequestOpt{}
109110
if bwForce {
110111
opts = append(opts, bitwarden.OptForce())
@@ -123,7 +124,7 @@ func bwAuth(w *tablewriter.Writer, _ []string) error {
123124
}
124125
}
125126

126-
func bwFolders(w *tablewriter.Writer, _ []string) error {
127+
func bwFolders(_ context.Context, w *tablewriter.Writer, _ []string) error {
127128
opts := []bitwarden.RequestOpt{}
128129
if bwForce {
129130
opts = append(opts, bitwarden.OptForce())
@@ -157,7 +158,7 @@ func bwFolders(w *tablewriter.Writer, _ []string) error {
157158
return w.Write(result)
158159
}
159160

160-
func bwLogins(w *tablewriter.Writer, _ []string) error {
161+
func bwLogins(_ context.Context, w *tablewriter.Writer, _ []string) error {
161162
opts := []bitwarden.RequestOpt{}
162163
if bwForce {
163164
opts = append(opts, bitwarden.OptForce())
@@ -205,7 +206,7 @@ func bwLogins(w *tablewriter.Writer, _ []string) error {
205206
return w.Write(result)
206207
}
207208

208-
func bwGetPassword(w *tablewriter.Writer, _ []string) error {
209+
func bwGetPassword(_ context.Context, w *tablewriter.Writer, _ []string) error {
209210
return ErrNotImplemented
210211
}
211212

cmd/api/cmd.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"context"
45
"fmt"
56

67
"github.com/djthorpe/go-tablewriter"
@@ -22,7 +23,7 @@ type Fn struct {
2223
Description string
2324
MinArgs uint
2425
MaxArgs uint
25-
Call func(*tablewriter.Writer, []string) error
26+
Call func(context.Context, *tablewriter.Writer, []string) error
2627
}
2728

2829
///////////////////////////////////////////////////////////////////////////////

cmd/api/flags.go

Lines changed: 102 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package main
22

33
import (
4+
"errors"
45
"flag"
56
"fmt"
7+
"io"
68
"os"
79
"runtime"
10+
"strings"
811
"time"
912

1013
"github.com/mutablelogic/go-client"
@@ -18,6 +21,9 @@ type Flags struct {
1821
*flag.FlagSet
1922

2023
cmds []Cmd
24+
cmd *Cmd
25+
root string
26+
args []string
2127
names map[string]*Value
2228
}
2329

@@ -32,7 +38,8 @@ type flagType uint
3238
// GLOBALS
3339

3440
var (
35-
ErrHelp = flag.ErrHelp
41+
ErrHelp = flag.ErrHelp
42+
ErrInstall = errors.New("install")
3643
)
3744

3845
const (
@@ -67,19 +74,48 @@ func (flags *Flags) Register(c Cmd) {
6774
flags.cmds = append(flags.cmds, c)
6875
}
6976

70-
func (flags *Flags) Parse(args []string) error {
77+
func (flags *Flags) Parse(args []string) (*Fn, []string, error) {
7178
// Parse command line
72-
if err := flags.FlagSet.Parse(args); err != nil {
73-
if err == flag.ErrHelp {
79+
err := flags.FlagSet.Parse(args)
80+
81+
// If there is a version argument, print the version and exit
82+
if flags.NArg() == 1 {
83+
switch flags.Arg(0) {
84+
case "version":
85+
flags.PrintVersion()
86+
return nil, nil, ErrHelp
87+
case "help":
7488
flags.PrintUsage()
89+
return nil, nil, ErrHelp
90+
case ErrInstall.Error():
91+
return nil, nil, ErrInstall
7592
}
76-
return err
7793
}
7894

79-
// If there is a version argument, print the version and exit
80-
if flags.NArg() == 1 && flags.Arg(0) == "version" {
81-
flags.PrintVersion()
82-
return ErrHelp
95+
// If the name of the command is the same as the name of the application
96+
if cmd := flags.getCommandSet(flags.Name()); cmd != nil {
97+
flags.cmd = cmd
98+
flags.root = cmd.Name
99+
flags.args = flags.Args()
100+
} else if flags.NArg() > 0 {
101+
if cmd := flags.getCommandSet(flags.Arg(0)); cmd != nil {
102+
flags.cmd = cmd
103+
flags.root = strings.Join([]string{flags.Name(), cmd.Name}, " ")
104+
flags.args = flags.Args()[1:]
105+
}
106+
}
107+
108+
// Print usage
109+
if err != nil {
110+
if err != flag.ErrHelp {
111+
fmt.Fprintf(os.Stderr, "%v: %v\n", flags.cmd.Name, err)
112+
} else {
113+
flags.PrintUsage()
114+
}
115+
return nil, nil, err
116+
} else if flags.cmd == nil {
117+
fmt.Fprintln(os.Stderr, "Unknown command, try -help")
118+
return nil, nil, ErrHelp
83119
}
84120

85121
// Set client options
@@ -89,29 +125,27 @@ func (flags *Flags) Parse(args []string) error {
89125
opts = append(opts, client.OptTrace(flags.Output(), flags.GetBool("verbose")))
90126
}
91127

92-
// Parse the commands
93-
if flags.NArg() > 0 {
94-
if cmd := flags.GetCommandSet(flags.Arg(0)); cmd != nil {
95-
if err := cmd.Parse(flags, opts...); err != nil {
96-
fmt.Fprintf(os.Stderr, "%v: %v\n", cmd.Name, err)
97-
return err
98-
}
99-
}
128+
// If there is a help argument, print the help and exit
129+
if flags.NArg() == 1 && flags.Arg(0) == "help" || flags.cmd == nil {
130+
flags.PrintUsage()
131+
return nil, nil, ErrHelp
132+
} else if err := flags.cmd.Parse(flags, opts...); err != nil {
133+
fmt.Fprintf(os.Stderr, "%v: %v\n", flags.cmd.Name, err)
134+
return nil, nil, err
100135
}
101136

102-
// Return success
103-
return nil
104-
}
105-
106-
// GetCommandSet returns a command set from a name, or nil if the command set does
107-
// not exist
108-
func (flags *Flags) GetCommandSet(name string) *Cmd {
109-
for _, cmd := range flags.cmds {
110-
if cmd.Name == name {
111-
return &cmd
112-
}
137+
// Set the function to call
138+
fn, args, err := flags.cmd.Get(flags.args)
139+
if err != nil {
140+
fmt.Fprintf(os.Stderr, "%v: %v\n", flags.cmd.Name, err)
141+
return nil, nil, err
142+
} else if fn == nil {
143+
fmt.Fprintln(os.Stderr, "Unknown command, try -help")
144+
return nil, nil, ErrHelp
113145
}
114-
return nil
146+
147+
// Return success
148+
return fn, args, nil
115149
}
116150

117151
// Get returns the value of a flag, and returns true if the flag exists
@@ -123,6 +157,11 @@ func (flags *Flags) Get(name string) (string, bool) {
123157
}
124158
}
125159

160+
// Get the current command set
161+
func (flags *Flags) Cmd() *Cmd {
162+
return flags.cmd
163+
}
164+
126165
///////////////////////////////////////////////////////////////////////////////
127166
// PUBLIC METHODS
128167

@@ -156,33 +195,33 @@ func (flags *Flags) PrintVersion() {
156195
// PrintUsage prints the usage of the application
157196
func (flags *Flags) PrintUsage() {
158197
w := flags.Output()
159-
if flags.NArg() == 1 {
160-
cmd := flags.GetCommandSet(flags.Arg(0))
161-
if cmd != nil {
162-
flags.PrintCommandUsage(cmd)
163-
}
198+
if flags.cmd != nil {
199+
flags.PrintCommandUsage(flags.cmd)
164200
} else {
165-
fmt.Fprintln(w, "Name:", flags.Name())
201+
fmt.Fprintln(w, "Name:", flags.root)
166202
fmt.Fprintln(w, " General command-line interface to API clients")
167203
fmt.Fprintln(w, "")
168204

169205
// Command Sets
170206
fmt.Fprintln(w, "Command Sets:")
171207
for _, cmd := range flags.cmds {
172-
fmt.Fprintln(w, " ", flags.Name(), cmd.Name)
208+
fmt.Fprintln(w, " ", flags.root, cmd.Name)
173209
fmt.Fprintln(w, " ", cmd.Description)
174210
fmt.Fprintln(w, "")
175211
}
176212

177213
// Help
178214
fmt.Fprintln(w, "Help:")
179-
fmt.Fprintln(w, " ", flags.Name(), "version")
215+
fmt.Fprintln(w, " ", flags.root, "version")
180216
fmt.Fprintln(w, " ", "Return the version of the application")
181217
fmt.Fprintln(w, "")
218+
fmt.Fprintln(w, " ", flags.root, "install")
219+
fmt.Fprintln(w, " ", "Install symlinks for command calling")
220+
fmt.Fprintln(w, "")
182221

183222
// Help for command sets
184223
for _, cmd := range flags.cmds {
185-
fmt.Fprintln(w, " ", flags.Name(), "-help", cmd.Name)
224+
fmt.Fprintln(w, " ", flags.root, "-help", cmd.Name)
186225
fmt.Fprintln(w, " ", "Display", cmd.Name, "command syntax")
187226
fmt.Fprintln(w, "")
188227
}
@@ -200,14 +239,14 @@ func (flags *Flags) PrintGlobalFlags() {
200239
// PrintCommandUsage prints the usage of a commandset
201240
func (flags *Flags) PrintCommandUsage(cmd *Cmd) {
202241
w := flags.Output()
203-
fmt.Fprintln(w, "Name:", flags.Name(), cmd.Name)
242+
fmt.Fprintln(w, "Name:", flags.root)
204243
fmt.Fprintln(w, " ", cmd.Description)
205244
fmt.Fprintln(w, "")
206245

207246
// Help for command sets
208247
fmt.Fprintln(w, "Commands:")
209248
for _, fn := range cmd.Fn {
210-
fmt.Fprintln(w, " ", flags.Name(), cmd.Name, fn.Name)
249+
fmt.Fprintln(w, " ", flags.root, fn.Name)
211250
fmt.Fprintln(w, " ", fn.Description)
212251
fmt.Fprintln(w, "")
213252
}
@@ -224,13 +263,21 @@ func (flags *Flags) PrintCommandFlags(cmd string) {
224263
} else {
225264
fmt.Fprintf(w, "Flags for %v:\n", cmd)
226265
}
227-
flags.VisitAll(func(f *flag.Flag) {
228-
if flags.names[f.Name].cmd == cmd {
229-
fmt.Fprintf(w, " -%v: %v\n", f.Name, f.Usage)
266+
flags.VisitAll(func(flag *flag.Flag) {
267+
if flags.names[flag.Name].cmd == cmd {
268+
printFlag(w, flag)
230269
}
231270
})
232271
}
233272

273+
func printFlag(w io.Writer, f *flag.Flag) {
274+
fmt.Fprintf(w, " -%v", f.Name)
275+
if len(f.DefValue) > 0 {
276+
fmt.Fprintf(w, " (default %q)", f.DefValue)
277+
}
278+
fmt.Fprintf(w, "\n %v\n\n", f.Usage)
279+
}
280+
234281
///////////////////////////////////////////////////////////////////////////////
235282
// PUBLIC METHODS - SET FLAGS
236283

@@ -315,3 +362,15 @@ func (flags *Flags) GetString(name string) string {
315362
return os.ExpandEnv(value)
316363
}
317364
}
365+
366+
///////////////////////////////////////////////////////////////////////////////
367+
// PRIVATE METHODS
368+
369+
func (flags *Flags) getCommandSet(name string) *Cmd {
370+
for _, cmd := range flags.cmds {
371+
if cmd.Name == name {
372+
return &cmd
373+
}
374+
}
375+
return nil
376+
}

0 commit comments

Comments
 (0)