|
5 | 5 | -export([main/1]). |
6 | 6 |
|
7 | 7 | main(Args) -> |
8 | | - case run_cli(Args) of |
9 | | - ok -> |
10 | | - erlang:halt(); |
11 | | - {error, ErrorMsg} -> |
12 | | - io:format(standard_error, "Error: ~ts~n", [ErrorMsg]), |
13 | | - erlang:halt(1) |
14 | | - end. |
| 8 | + Ret = run_cli(Args), |
| 9 | + io:format(standard_error, "Ret: ~p~n", [Ret]), |
| 10 | + erlang:halt(). |
15 | 11 |
|
16 | 12 | run_cli(Args) -> |
17 | 13 | maybe |
18 | 14 | Progname = escript:script_name(), |
19 | 15 | add_rabbitmq_code_path(Progname), |
20 | 16 |
|
21 | | - {ok, ArgMap, RemainingArgs} ?= parse_args(Progname, Args), |
22 | | - Nodename = lookup_rabbitmq_nodename(ArgMap), |
23 | | - {ok, _} ?= net_kernel:start(undefined, #{name_domain => shortnames}), |
24 | | - |
25 | | - {ok, IO} ?= rabbit_cli_io:start_link(), |
26 | | - Ret = case net_kernel:connect_node(Nodename) of |
27 | | - true -> |
28 | | - catch run_command( |
29 | | - Nodename, Progname, ArgMap, RemainingArgs, IO); |
30 | | - false -> |
31 | | - catch run_command( |
32 | | - undefined, Progname, ArgMap, RemainingArgs, IO) |
33 | | - end, |
34 | | - io:format("Ret = ~p~n", [Ret]), |
35 | | - rabbit_cli_io:stop(IO), |
36 | | - ok |
| 17 | + PartialArgparseDef = argparse_def(), |
| 18 | + {ok, |
| 19 | + PartialArgMap, |
| 20 | + PartialCmdPath, |
| 21 | + PartialCommand} ?= initial_parse(Progname, Args, PartialArgparseDef), |
| 22 | + |
| 23 | + %% Get remote node name and prepare Erlang distribution. |
| 24 | + Nodename = lookup_rabbitmq_nodename(PartialArgMap), |
| 25 | + {ok, _} ?= net_kernel:start( |
| 26 | + undefined, #{name_domain => shortnames}), |
| 27 | + |
| 28 | + {ok, IO} ?= rabbit_cli_io:start_link(Progname), |
| 29 | + try |
| 30 | + %% Can we reach the remote node? |
| 31 | + case net_kernel:connect_node(Nodename) of |
| 32 | + true -> |
| 33 | + maybe |
| 34 | + %% We can query the argparse definition from the |
| 35 | + %% remote node to know the commands it supports and |
| 36 | + %% proceed with the execution. |
| 37 | + ArgparseDef = get_final_argparse_def(Nodename), |
| 38 | + {ok, |
| 39 | + ArgMap, |
| 40 | + CmdPath, |
| 41 | + Command} ?= final_parse(Progname, Args, ArgparseDef), |
| 42 | + run_command( |
| 43 | + Nodename, ArgparseDef, |
| 44 | + Progname, ArgMap, CmdPath, Command, |
| 45 | + IO) |
| 46 | + end; |
| 47 | + false -> |
| 48 | + %% We can't reach the remote node. Let's fallback |
| 49 | + %% to a local execution. |
| 50 | + run_command( |
| 51 | + undefined, PartialArgparseDef, |
| 52 | + Progname, PartialArgMap, PartialCmdPath, |
| 53 | + PartialCommand, IO) |
| 54 | + end |
| 55 | + after |
| 56 | + rabbit_cli_io:stop(IO) |
| 57 | + end |
37 | 58 | end. |
38 | 59 |
|
39 | 60 | add_rabbitmq_code_path(Progname) -> |
@@ -73,34 +94,45 @@ argparse_def() -> |
73 | 94 | short => $V, |
74 | 95 | help => |
75 | 96 | "Display version and exit"} |
76 | | - ]}. |
| 97 | + ], |
| 98 | + |
| 99 | + commands => #{}}. |
77 | 100 |
|
78 | | -parse_args(Progname, Args) -> |
79 | | - Definition = argparse_def(), |
| 101 | +initial_parse(Progname, Args, ArgparseDef) -> |
80 | 102 | Options = #{progname => Progname}, |
81 | | - case partial_parse(Args, Definition, Options) of |
82 | | - {ok, ArgMap, _CmdPath, _Command, RemainingArgs} -> |
83 | | - {ok, ArgMap, RemainingArgs}; |
| 103 | + case partial_parse(Args, ArgparseDef, Options) of |
| 104 | + {ok, ArgMap, CmdPath, Command, _RemainingArgs} -> |
| 105 | + {ok, ArgMap, CmdPath, Command}; |
84 | 106 | {error, _} = Error-> |
85 | 107 | Error |
86 | 108 | end. |
87 | 109 |
|
88 | | -partial_parse(Args, Definition, Options) -> |
89 | | - partial_parse(Args, Definition, Options, []). |
| 110 | +partial_parse(Args, ArgparseDef, Options) -> |
| 111 | + partial_parse(Args, ArgparseDef, Options, []). |
90 | 112 |
|
91 | | -partial_parse(Args, Definition, Options, RemainingArgs) -> |
92 | | - case argparse:parse(Args, Definition, Options) of |
| 113 | +partial_parse(Args, ArgparseDef, Options, RemainingArgs) -> |
| 114 | + case argparse:parse(Args, ArgparseDef, Options) of |
93 | 115 | {ok, ArgMap, CmdPath, Command} -> |
94 | 116 | RemainingArgs1 = lists:reverse(RemainingArgs), |
95 | 117 | {ok, ArgMap, CmdPath, Command, RemainingArgs1}; |
96 | 118 | {error, {_CmdPath, undefined, Arg, <<>>}} -> |
97 | 119 | Args1 = Args -- [Arg], |
98 | 120 | RemainingArgs1 = [Arg | RemainingArgs], |
99 | | - partial_parse(Args1, Definition, Options, RemainingArgs1); |
| 121 | + partial_parse(Args1, ArgparseDef, Options, RemainingArgs1); |
100 | 122 | {error, _} = Error -> |
101 | 123 | Error |
102 | 124 | end. |
103 | 125 |
|
| 126 | +get_final_argparse_def(Nodename) -> |
| 127 | + ArgparseDef1 = argparse_def(), |
| 128 | + ArgparseDef2 = erpc:call(Nodename, rabbit_cli_commands, argparse_def, []), |
| 129 | + ArgparseDef = maps:merge(ArgparseDef1, ArgparseDef2), |
| 130 | + ArgparseDef. |
| 131 | + |
| 132 | +final_parse(Progname, Args, ArgparseDef) -> |
| 133 | + Options = #{progname => Progname}, |
| 134 | + argparse:parse(Args, ArgparseDef, Options). |
| 135 | + |
104 | 136 | lookup_rabbitmq_nodename(#{node := Nodename}) -> |
105 | 137 | Nodename1 = complete_nodename(Nodename), |
106 | 138 | Nodename1; |
@@ -138,6 +170,15 @@ complete_nodename(Nodename) -> |
138 | 170 | list_to_atom(Nodename) |
139 | 171 | end. |
140 | 172 |
|
| 173 | +run_command( |
| 174 | + _Nodename, ArgparseDef, _Progname, #{help := true}, CmdPath, _Command, IO) -> |
| 175 | + rabbit_cli_io:display_help(IO, CmdPath, ArgparseDef); |
| 176 | +run_command(Nodename, _ArgparseDef, Progname, ArgMap, CmdPath, Command, IO) -> |
| 177 | + erpc:call( |
| 178 | + Nodename, |
| 179 | + rabbit_cli_commands, run_command, |
| 180 | + [Progname, ArgMap, CmdPath, Command, IO]). |
| 181 | + |
141 | 182 | %lookup_command_map(Nodename) -> |
142 | 183 | % %% Order of operations: |
143 | 184 | % %% 1. refresh the cached copy: |
@@ -178,17 +219,3 @@ complete_nodename(Nodename) -> |
178 | 219 | % nomatch -> |
179 | 220 | % true |
180 | 221 | % end. |
181 | | - |
182 | | -run_command(undefined, Progname, #{help := true}, _RemainingArgs, IO) -> |
183 | | - Definition = argparse_def(), |
184 | | - rabbit_cli_io:display_help(IO, Progname, [], Definition); |
185 | | -run_command(Nodename, Progname, ArgMap, RemainingArgs, IO) -> |
186 | | - try |
187 | | - erpc:call( |
188 | | - Nodename, |
189 | | - rabbit_cli_commands, run_command, |
190 | | - [Progname, ArgMap, RemainingArgs, IO]) |
191 | | - catch |
192 | | - error:{erpc, Reason} -> |
193 | | - {error, Reason} |
194 | | - end. |
|
0 commit comments