1515
1616
1717defmodule RabbitMQ.CLI.Ctl.CommandModules do
18+ @ commands_ns ~r/ RabbitMQ.CLI.(.*).Commands/
19+
1820 def module_map do
1921 case Application . get_env ( :rabbitmqctl , :commands ) do
2022 nil -> load ;
@@ -41,28 +43,32 @@ defmodule RabbitMQ.CLI.Ctl.CommandModules do
4143 end
4244
4345 defp load_commands ( scope ) do
44- modules = loadable_modules ( )
45- modules
46- |> Enum . filter ( fn ( path ) ->
47- to_string ( path ) =~ ~r/ RabbitMQ.CLI.*.Commands/
46+ ctl_and_plugin_modules
47+ |> Enum . filter ( fn ( mod ) ->
48+ to_string ( mod ) =~ @ commands_ns
49+ and
50+ implements_command_behaviour? ( mod )
51+ and
52+ command_in_scope ( mod , scope )
4853 end )
49- |> Enum . map ( fn ( path ) ->
50- Path . rootname ( path , '.beam' )
51- |> String . to_atom
52- |> Code . ensure_loaded
53- end )
54- |> Enum . filter_map ( fn ( { res , _ } ) -> res == :module end ,
55- fn ( { _ , mod } ) -> command_tuple ( mod ) end )
56- |> Enum . filter ( fn ( { _ , cmd } ) -> command_in_scope ( cmd , scope ) end )
54+ |> Enum . map ( & command_tuple / 1 )
5755 |> Map . new
5856 end
5957
60- defp loadable_modules do
61- :code . get_path ( )
62- |> Enum . flat_map ( fn ( path ) ->
63- { :ok , modules } = :erl_prim_loader . list_dir ( path )
64- modules
65- end )
58+ defp ctl_and_plugin_modules do
59+ # No plugins so far
60+ applications = [ :rabbitmqctl ]
61+ applications
62+ |> Enum . flat_map ( fn ( app ) -> Application . spec ( app , :modules ) end )
63+ end
64+
65+
66+ defp implements_command_behaviour? ( nil ) do
67+ false
68+ end
69+ defp implements_command_behaviour? ( module ) do
70+ Enum . member? ( module . module_info ( :attributes ) [ :behaviour ] || [ ] ,
71+ RabbitMQ.CLI.CommandBehaviour )
6672 end
6773
6874 defp command_tuple ( cmd ) do
@@ -107,8 +113,20 @@ defmodule RabbitMQ.CLI.Ctl.CommandModules do
107113 false
108114 end
109115 defp command_in_scope ( cmd , scope ) do
110- cmd
111- |> to_string
112- |> String . contains? ( "RabbitMQ.CLI.#{ scope } .Commands" )
116+ Enum . member? ( command_scopes ( cmd ) , scope )
117+ end
118+
119+ defp command_scopes ( cmd ) do
120+ case :erlang . function_exported ( cmd , :scopes , 0 ) do
121+ true ->
122+ cmd . scopes ( )
123+ false ->
124+ @ commands_ns
125+ |> Regex . run ( to_string ( cmd ) , capture: :all_but_first )
126+ |> List . first
127+ |> to_snake_case
128+ |> String . to_atom
129+ |> List . wrap
130+ end
113131 end
114132end
0 commit comments