@@ -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.
1610type 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.
4970type 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
5598func (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