Skip to content

Commit 63f58e9

Browse files
committed
Simplify API
1 parent 2c8df91 commit 63f58e9

File tree

2 files changed

+242
-131
lines changed

2 files changed

+242
-131
lines changed

‎cobrakai.go‎

Lines changed: 89 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -6,50 +6,93 @@ import (
66
"github.com/spf13/cobra"
77
)
88

9-
// Executer is the execution entry point.
10-
// The args are usually filled with os.Args[1:].
11-
type Executer interface {
12-
Execute(ctx context.Context, args []string) (*Commandeer, error)
13-
}
14-
159
// Commander is the interface that must be implemented by all commands.
1610
type Commander interface {
11+
// The name of the command.
1712
Name() string
13+
14+
// The command execution.
1815
Run(ctx context.Context, args []string) error
16+
17+
// Init called on all commands in this tree, before execution, starting from the root.
18+
// This is the place to evaluate flags and set up the command.
19+
Init(*Commandeer) error
20+
21+
// WithCobraCommand is called when the cobra command is created.
22+
// This is where the flags, short and long description etc. are added.
1923
WithCobraCommand(*cobra.Command) error
24+
25+
// Commands returns the sub commands, if any.
26+
Commands() []Commander
2027
}
2128

22-
type root struct {
23-
c *Commandeer
29+
// Executer is the execution entry point.
30+
// The args are usually filled with os.Args[1:].
31+
type Executer interface {
32+
Execute(ctx context.Context, args []string) (*Commandeer, error)
2433
}
2534

26-
func (r *root) Execute(ctx context.Context, args []string) (*Commandeer, error) {
27-
r.c.CobraCommand.SetArgs(args)
28-
cobraCommand, err := r.c.CobraCommand.ExecuteContextC(ctx)
29-
if err != nil {
30-
return nil, err
35+
// New creates a new Executer from the command tree in Commander.
36+
func New(rootCmd Commander) (Executer, error) {
37+
rootCd := &Commandeer{
38+
Command: rootCmd,
3139
}
32-
// Find the commandeer that was executed.
33-
var find func(*cobra.Command, *Commandeer) *Commandeer
34-
find = func(what *cobra.Command, in *Commandeer) *Commandeer {
35-
if in.CobraCommand == what {
36-
return in
40+
rootCd.Root = rootCd
41+
42+
// Add all commands recursively.
43+
var addCommands func(cd *Commandeer, cmd Commander)
44+
addCommands = func(cd *Commandeer, cmd Commander) {
45+
cd2 := &Commandeer{
46+
Root: rootCd,
47+
Parent: cd,
48+
Command: cmd,
3749
}
38-
for _, in2 := range in.commandeers {
39-
if found := find(what, in2); found != nil {
40-
return found
41-
}
50+
cd.commandeers = append(cd.commandeers, cd2)
51+
for _, c := range cmd.Commands() {
52+
addCommands(cd2, c)
4253
}
43-
return nil
54+
4455
}
45-
return find(cobraCommand, r.c), nil
56+
57+
for _, cmd := range rootCmd.Commands() {
58+
addCommands(rootCd, cmd)
59+
}
60+
61+
if err := rootCd.compile(); err != nil {
62+
return nil, err
63+
}
64+
65+
return &root{c: rootCd}, nil
66+
4667
}
4768

4869
// Commandeer holds the state of a command and its subcommands.
4970
type Commandeer struct {
5071
Command Commander
5172
CobraCommand *cobra.Command
52-
commandeers []*Commandeer
73+
74+
Root *Commandeer
75+
Parent *Commandeer
76+
commandeers []*Commandeer
77+
}
78+
79+
func (c *Commandeer) init() error {
80+
// Start from the root and initialize all commands recursively.
81+
// root is always set.
82+
cd := c.Root
83+
var initc func(*Commandeer) error
84+
initc = func(cd *Commandeer) error {
85+
if err := cd.Command.Init(cd); err != nil {
86+
return err
87+
}
88+
for _, cc := range cd.commandeers {
89+
if err := initc(cc); err != nil {
90+
return err
91+
}
92+
}
93+
return nil
94+
}
95+
return initc(cd)
5396
}
5497

5598
func (c *Commandeer) compile() error {
@@ -58,6 +101,9 @@ func (c *Commandeer) compile() error {
58101
RunE: func(cmd *cobra.Command, args []string) error {
59102
return c.Command.Run(cmd.Context(), args)
60103
},
104+
PreRunE: func(cmd *cobra.Command, args []string) error {
105+
return c.init()
106+
},
61107
}
62108

63109
// This is where the flags, short and long description etc. are added
@@ -74,57 +120,28 @@ func (c *Commandeer) compile() error {
74120
return nil
75121
}
76122

77-
// WithCommandeer allows chaining of commandeers.
78-
type WithCommandeer func(*Commandeer)
123+
type root struct {
124+
c *Commandeer
125+
}
79126

80-
// R creates the execution entry poing given a root command and a chain of nested commands.
81-
func R(command Commander, wcs ...WithCommandeer) (Executer, error) {
82-
c := &Commandeer{
83-
Command: command,
84-
}
85-
for _, wc := range wcs {
86-
wc(c)
87-
}
88-
if err := c.compile(); err != nil {
127+
func (r *root) Execute(ctx context.Context, args []string) (*Commandeer, error) {
128+
r.c.CobraCommand.SetArgs(args)
129+
cobraCommand, err := r.c.CobraCommand.ExecuteContextC(ctx)
130+
if err != nil {
89131
return nil, err
90132
}
91-
return &root{c: c}, nil
92-
}
93-
94-
// C creates nested commands.
95-
func C(command Commander, wcs ...WithCommandeer) WithCommandeer {
96-
return func(parent *Commandeer) {
97-
cd := &Commandeer{
98-
Command: command,
133+
// Find the commandeer that was executed.
134+
var find func(*cobra.Command, *Commandeer) *Commandeer
135+
find = func(what *cobra.Command, in *Commandeer) *Commandeer {
136+
if in.CobraCommand == what {
137+
return in
99138
}
100-
parent.commandeers = append(parent.commandeers, cd)
101-
for _, wc := range wcs {
102-
wc(cd)
139+
for _, in2 := range in.commandeers {
140+
if found := find(what, in2); found != nil {
141+
return found
142+
}
103143
}
144+
return nil
104145
}
105-
}
106-
107-
// SimpleCommand creates a simple command that does not take any flags.
108-
func SimpleCommand(name string, run func(ctx context.Context, args []string) error) Commander {
109-
return &simpleCommand{
110-
name: name,
111-
run: run,
112-
}
113-
}
114-
115-
type simpleCommand struct {
116-
name string
117-
run func(ctx context.Context, args []string) error
118-
}
119-
120-
func (c *simpleCommand) Name() string {
121-
return c.name
122-
}
123-
124-
func (c *simpleCommand) Run(ctx context.Context, args []string) error {
125-
return c.run(ctx, args)
126-
}
127-
128-
func (c *simpleCommand) WithCobraCommand(cmd *cobra.Command) error {
129-
return nil
146+
return find(cobraCommand, r.c), nil
130147
}

0 commit comments

Comments
 (0)