Show timeout in help messages only for commands supporting timeout.

Removed timeout from default parsing options. Now every command
has to specify timeout in it's own switches.
If a command has timeout in switches - there will be help displayed
for this option in usage output.
This commit is contained in:
Daniil Fedotov 2018-03-07 18:28:21 +00:00
parent 0c83c05ec1
commit aef04bef84
32 changed files with 131 additions and 97 deletions

View File

@ -167,7 +167,7 @@ defmodule RabbitMQ.CLI.Core.Parser do
[node: :atom,
quiet: :boolean,
dry_run: :boolean,
timeout: :integer,
# timeout: :integer,
vhost: :string,
longnames: :boolean,
formatter: :string,
@ -187,7 +187,7 @@ defmodule RabbitMQ.CLI.Core.Parser do
[p: :vhost,
n: :node,
q: :quiet,
t: :timeout,
# t: :timeout,
l: :longnames]
end

View File

@ -17,8 +17,8 @@
defmodule RabbitMQ.CLI.Ctl.Commands.DeleteQueueCommand do
@behaviour RabbitMQ.CLI.CommandBehaviour
def switches(), do: [if_empty: :boolean, if_unused: :boolean]
def aliases(), do: [e: :if_empty, u: :is_unused]
def switches(), do: [if_empty: :boolean, if_unused: :boolean, timeout: :integer]
def aliases(), do: [e: :if_empty, u: :is_unused, t: :timeout]
def usage(), do: "delete_queue queue_name [--if_empty|-e] [--if_unused|-u]"

View File

@ -39,8 +39,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.HelpCommand do
all_usage(opts);
command ->
Enum.join([base_usage(command, opts)] ++
options_usage(opts) ++
input_types(command), "\n")
options_usage() ++
additional_usage(command), "\n\n")
end
end
def run(_, opts) do
@ -61,57 +61,42 @@ defmodule RabbitMQ.CLI.Ctl.Commands.HelpCommand do
def all_usage(opts) do
Enum.join(tool_usage(program_name(opts)) ++
options_usage(opts) ++
["Commands:"] ++
commands() ++
input_types(), "\n")
options_usage() ++
[Enum.join(["Commands:"] ++ commands(), "\n")] ++
additional_usage(), "\n\n")
end
def usage(), do: "help <command>"
defp tool_usage(tool_name) do
maybe_timeout = case supports_timeout(tool_name) do
true -> " [-t <timeout>]"
false -> ""
end
["Usage:",
"#{tool_name} [-n <node>]" <> maybe_timeout <> " [-l] [-q] <command> [<command options>]"]
["\nUsage:\n" <>
"#{tool_name} [-n <node>] [-l] [-q] <command> [<command options>]"]
end
def base_usage(command, opts) do
tool_name = program_name(opts)
maybe_timeout = case supports_timeout(tool_name) do
maybe_timeout = case command_supports_timeout(command) do
true -> " [-t <timeout>]"
false -> ""
end
Enum.join(["Usage:",
"#{tool_name} [-n <node>]" <> maybe_timeout <> " [-l] [-q] " <>
flatten_string(command.usage())], "\n")
Enum.join(["\nUsage:\n",
"#{tool_name} [-n <node>] [-l] [-q] " <>
flatten_string(command.usage(), maybe_timeout)])
end
defp flatten_string(list) when is_list(list) do
Enum.join(list, "\n")
defp flatten_string(list, additional) when is_list(list) do
list
|> Enum.map(fn(line) -> line <> additional end)
|> Enum.join("\n")
end
defp flatten_string(str) when is_binary(str) do
str
defp flatten_string(str, additional) when is_binary(str) do
str <> additional
end
defp options_usage(opts) do
tool_name = program_name(opts)
{maybe_timeout, timeout_explanation} = case supports_timeout(tool_name) do
true ->
{"
-t timeout",
"
Operation timeout in seconds. Only applicable to \"list\" commands. " <>
"Default is \"infinity\"."};
false -> {"", ""}
end
["
General options:
defp options_usage() do
["General options:
-n node
-q quiet" <> maybe_timeout <> "
-q quiet
-l longnames
Default node is \"rabbit@server\", where `server` is the local hostname. On a host
@ -122,13 +107,13 @@ the correct suffix to use after the \"@\" sign. See rabbitmq-server(1) for
details of configuring the RabbitMQ broker.
Quiet output mode is selected with the \"-q\" flag. Informational messages are
suppressed when quiet mode is in effect." <> timeout_explanation <> "
suppressed when quiet mode is in effect.
If RabbitMQ broker uses long node names for erlang distribution, \"longnames\"
option should be specified.
Some commands accept an optional virtual host parameter for which
to display results. The default value is \"/\".\n"]
to display results. The default value is \"/\"."]
end
def commands() do
@ -137,32 +122,54 @@ to display results. The default value is \"/\".\n"]
CommandModules.module_map
|> Map.values
|> Enum.sort
|> Enum.map(&(&1.usage))
|> Enum.map( fn(cmd) ->
maybe_timeout = case command_supports_timeout(cmd) do
true -> "[-t <timeout>]"
false -> ""
end
case cmd.usage() do
bin when is_binary(bin) ->
bin <> maybe_timeout;
list when is_list(list) ->
Enum.map(list, fn(line) -> line <> maybe_timeout end)
end
end)
|> List.flatten
|> Enum.sort
|> Enum.map(fn(cmd_usage) -> " #{cmd_usage}" end)
end
defp input_types(command) do
defp additional_usage(command) do
if :erlang.function_exported(command, :usage_additional, 0) do
[command.usage_additional()]
case command.usage_additional() do
list when is_list(list) -> ["<timeout> - operation timeout in seconds. Default is \"infinity\"." | list];
bin when is_binary(bin) -> ["<timeout> - operation timeout in seconds. Default is \"infinity\".", bin]
end
else
[]
case command_supports_timeout(command) do
true ->
["<timeout> - operation timeout in seconds. Default is \"infinity\"."];
false ->
[]
end
end
end
defp input_types() do
[CommandModules.module_map
defp additional_usage() do
["<timeout> - operation timeout in seconds. Default is \"infinity\".",
CommandModules.module_map
|> Map.values
|> Enum.filter(&:erlang.function_exported(&1, :usage_additional, 0))
|> Enum.map(&(&1.usage_additional))
|> Enum.join("\n\n")]
end
defp supports_timeout(:'rabbitmqctl'), do: true
defp supports_timeout(:'rabbitmq-diagnostics'), do: true
defp supports_timeout(:'rabbitmq_diagnostics'), do: true
defp supports_timeout(_), do: false
defp command_supports_timeout(command) do
case :erlang.function_exported(command, :switches, 0) do
true -> nil != command.switches[:timeout];
false -> false
end
end
def banner(_,_), do: nil
end

View File

@ -29,6 +29,9 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListBindingsCommand do
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults([], opts) do
{~w(source_name source_kind
destination_name destination_kind

View File

@ -25,6 +25,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListConnectionsCommand do
def formatter(), do: RabbitMQ.CLI.Formatters.Table
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
@info_keys ~w(pid name port host peer_port peer_host ssl ssl_protocol
ssl_key_exchange ssl_cipher ssl_hash peer_cert_subject

View File

@ -25,6 +25,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListConsumersCommand do
def formatter(), do: RabbitMQ.CLI.Formatters.Table
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
@info_keys ~w(queue_name channel_pid consumer_tag
ack_required prefetch_count arguments)a

View File

@ -28,6 +28,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListExchangesCommand do
def info_keys(), do: @info_keys
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults([], opts) do
merge_defaults(~w(name type), opts)
@ -36,7 +38,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListExchangesCommand do
def merge_defaults(args, opts) do
{args, Map.merge(%{vhost: "/"}, opts)}
end
def validate(args, _) do
case InfoKeys.validate_info_keys(args, @info_keys) do
{:ok, _} -> :ok
@ -45,7 +47,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListExchangesCommand do
end
use RabbitMQ.CLI.Core.RequiresRabbitAppRunning
def run([_|_] = args, %{node: node_name, timeout: timeout, vhost: vhost}) do
info_keys = InfoKeys.prepare_info_keys(args)
RpcStream.receive_list_items(node_name, :rabbit_exchange, :info_all,
@ -62,6 +64,6 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListExchangesCommand do
"<exchangeinfoitem> must be a member of the list [" <>
Enum.join(@info_keys, ", ") <> "]."
end
def banner(_,%{vhost: vhost}), do: "Listing exchanges for vhost #{vhost} ..."
end

View File

@ -25,6 +25,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListGlobalParametersCommand do
end
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def validate([_|_], _) do
{:validation_failure, :too_many_args}
@ -32,7 +34,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListGlobalParametersCommand do
def validate([], _), do: :ok
use RabbitMQ.CLI.Core.RequiresRabbitAppRunning
def run([], %{node: node_name, timeout: timeout}) do
:rabbit_misc.rpc_call(node_name,
:rabbit_runtime_parameters,

View File

@ -22,6 +22,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListOperatorPoliciesCommand do
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts) do
{args, Map.merge(%{vhost: "/"}, opts)}

View File

@ -22,6 +22,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListParametersCommand do
def formatter(), do: RabbitMQ.CLI.Formatters.Table
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts) do
{args, Map.merge(%{vhost: "/"}, opts)}

View File

@ -21,6 +21,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListPermissionsCommand do
def formatter(), do: RabbitMQ.CLI.Formatters.Table
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts) do
{args, Map.merge(%{vhost: "/"}, opts)}

View File

@ -21,6 +21,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListPoliciesCommand do
def formatter(), do: RabbitMQ.CLI.Formatters.Table
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts) do
{args, Map.merge(%{vhost: "/"}, opts)}

View File

@ -41,7 +41,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListQueuesCommand do
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [offline: :boolean, online: :boolean, local: :boolean]
def switches(), do: [offline: :boolean, online: :boolean, local: :boolean, timeout: :integer]
def aliases(), do: [t: :timeout]
defp default_opts() do
%{vhost: "/", offline: false, online: false, local: false}
@ -103,8 +104,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListQueuesCommand do
end
def usage_additional() do
"<queueinfoitem> must be a member of the list [" <>
Enum.join(@info_keys, ", ") <> "]."
["<queueinfoitem> must be a member of the list [" <> Enum.join(@info_keys, ", ") <> "]."]
end
def banner(_,%{vhost: vhost, timeout: timeout}) do

View File

@ -21,6 +21,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListTopicPermissionsCommand do
def formatter(), do: RabbitMQ.CLI.Formatters.Table
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts) do
{args, Map.merge(%{vhost: "/"}, opts)}

View File

@ -34,7 +34,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListUnresponsiveQueuesCommand do
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [queue_timeout: :integer, local: :boolean]
def switches(), do: [queue_timeout: :integer, local: :boolean, timeout: :integer]
def aliases(), do: [t: :timeout]
defp default_opts() do
%{vhost: "/", local: false, queue_timeout: 15}

View File

@ -21,6 +21,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListUserPermissionsCommand do
def formatter(), do: RabbitMQ.CLI.Formatters.Table
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts), do: {args, opts}

View File

@ -21,6 +21,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListUserTopicPermissionsCommand do
def formatter(), do: RabbitMQ.CLI.Formatters.Table
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts), do: {args, opts}

View File

@ -21,6 +21,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListUsersCommand do
def formatter(), do: RabbitMQ.CLI.Formatters.Table
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts), do: {args, opts}

View File

@ -27,6 +27,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListVhostsCommand do
def info_keys(), do: @info_keys
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults([], opts), do: {["name"], opts}
def merge_defaults(args, opts), do: {args, opts}

View File

@ -19,6 +19,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.NodeHealthCheckCommand do
@default_timeout 70_000
def scopes(), do: [:ctl, :diagnostics]
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts) do
timeout = case opts[:timeout] do

View File

@ -18,6 +18,9 @@ defmodule RabbitMQ.CLI.Ctl.Commands.PurgeQueueCommand do
@behaviour RabbitMQ.CLI.CommandBehaviour
use RabbitMQ.CLI.DefaultOutput
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts) do
{args, Map.merge(%{vhost: "/"}, opts)}
end

View File

@ -18,6 +18,9 @@ alias RabbitMQ.CLI.Core.ExitCodes, as: ExitCodes
defmodule RabbitMQ.CLI.Ctl.Commands.RestartVhostCommand do
@behaviour RabbitMQ.CLI.CommandBehaviour
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts), do: {args, Map.merge(%{vhost: "/"}, opts)}
def validate([], _), do: :ok

View File

@ -20,12 +20,12 @@ defmodule RabbitMQ.CLI.Ctl.Commands.WaitCommand do
@behaviour RabbitMQ.CLI.CommandBehaviour
@default_timeout 10_000
def switches(), do: [pid: :integer]
def switches(), do: [pid: :integer, timeout: :integer]
def aliases(), do: ['P': :pid]
def aliases(), do: ['P': :pid, t: :timeout]
def scopes(), do: [:ctl, :diagnostics]
def merge_defaults(args, opts) do
timeout = case opts[:timeout] do
nil -> @default_timeout;

View File

@ -20,7 +20,8 @@ defmodule RabbitMQ.CLI.Diagnostics.Commands.CipherSuitesCommand do
def merge_defaults(args, opts), do: {args, Map.merge(%{openssl_format: false}, opts)}
def switches(), do: [openssl_format: :boolean]
def switches(), do: [openssl_format: :boolean, timeout: :integer]
def aliases(), do: [t: :timeout]
def validate(args, _) when length(args) > 0 do
{:validation_failure, :too_many_args}

View File

@ -17,6 +17,9 @@
defmodule RabbitMQ.CLI.Diagnostics.Commands.DiscoverPeersCommand do
@behaviour RabbitMQ.CLI.CommandBehaviour
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts), do: {args, opts}
def validate([_|_], _) do

View File

@ -17,6 +17,9 @@
defmodule RabbitMQ.CLI.Diagnostics.Commands.ErlangCookieHashCommand do
@behaviour RabbitMQ.CLI.CommandBehaviour
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts), do: {args, opts}
def validate(args, _) when length(args) > 0 do

View File

@ -17,7 +17,8 @@
defmodule RabbitMQ.CLI.Diagnostics.Commands.ErlangVersionCommand do
@behaviour RabbitMQ.CLI.CommandBehaviour
def switches(), do: [details: :boolean]
def switches(), do: [details: :boolean, timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts) do
{args, Map.merge(%{details: false}, opts)}

View File

@ -18,8 +18,9 @@ defmodule RabbitMQ.CLI.Diagnostics.Commands.MaybeStuckCommand do
@behaviour RabbitMQ.CLI.CommandBehaviour
use RabbitMQ.CLI.DefaultOutput
def switches(), do: []
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts), do: {args, opts}
def validate(args, _) when length(args) > 0 do
@ -35,5 +36,5 @@ defmodule RabbitMQ.CLI.Diagnostics.Commands.MaybeStuckCommand do
"Asking node #{node_name} to detect potentially stuck Erlang processes..."
end
def usage, do: "maybe_stuck"
def usage, do: "maybe_stuck"
end

View File

@ -19,7 +19,8 @@ defmodule RabbitMQ.CLI.Diagnostics.Commands.MemoryBreakdownCommand do
@behaviour RabbitMQ.CLI.CommandBehaviour
def switches(), do: [unit: :string]
def switches(), do: [unit: :string, timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts) do
{args, Map.merge(%{unit: "gb"}, opts)}

View File

@ -17,6 +17,9 @@
defmodule RabbitMQ.CLI.Diagnostics.Commands.ServerVersionCommand do
@behaviour RabbitMQ.CLI.CommandBehaviour
def switches(), do: [timeout: :integer]
def aliases(), do: [t: :timeout]
def merge_defaults(args, opts), do: {args, opts}
def validate(args, _) when length(args) > 0 do

View File

@ -113,30 +113,6 @@ defmodule ParserTest do
assert @subject.parse_global(["--node=rabbitmq@localhost"]) == {[], %{node: :"rabbitmq@localhost"}, []}
end
test "no commands, one integer --timeout value" do
assert @subject.parse_global(["--timeout=600"]) == {[], %{timeout: 600}, []}
end
test "no commands, one string --timeout value is invalid" do
assert @subject.parse_global(["--timeout=sandwich"]) == {[], %{}, [{"--timeout", "sandwich"}]}
end
test "no commands, one float --timeout value is invalid" do
assert @subject.parse_global(["--timeout=60.5"]) == {[], %{}, [{"--timeout", "60.5"}]}
end
test "no commands, one integer -t value" do
assert @subject.parse_global(["-t", "600"]) == {[], %{timeout: 600}, []}
end
test "no commands, one string -t value is invalid" do
assert @subject.parse_global(["-t", "sandwich"]) == {[], %{}, [{"-t", "sandwich"}]}
end
test "no commands, one float -t value is invalid" do
assert @subject.parse_global(["-t", "60.5"]) == {[], %{}, [{"-t", "60.5"}]}
end
test "no commands, one single-dash -p option" do
assert @subject.parse_global(["-p", "sandwich"]) == {[], %{vhost: "sandwich"}, []}
end

View File

@ -59,14 +59,14 @@ defmodule RabbitMQCtlTest do
command = []
assert capture_io(:stderr, fn ->
error_check(command, exit_usage())
end) =~ ~r/Usage:\n/
end) =~ ~r/\nUsage:\n/
end
test "Empty command with options shows usage, and exit with usage exit code" do
command = ["-n", "sandwich@pastrami"]
assert capture_io(:stderr, fn ->
error_check(command, exit_usage())
end) =~ ~r/Usage:\n/
end) =~ ~r/\nUsage:\n/
end
test "Short names without host connect properly" do
@ -78,21 +78,21 @@ defmodule RabbitMQCtlTest do
command = ["not_real"]
assert capture_io(:stderr, fn ->
error_check(command, exit_usage())
end) =~ ~r/Usage\:/
end) =~ ~r/\nUsage\:/
end
test "Extraneous arguments return a usage error" do
command = ["status", "extra"]
assert capture_io(:stderr, fn ->
error_check(command, exit_usage())
end) =~ ~r/given:\n\t.*\nUsage:\n.* status/
end) =~ ~r/given:\n\t.*\n\nUsage:\n.* status/
end
test "Insufficient arguments return a usage error" do
command = ["list_user_permissions"]
assert capture_io(:stderr, fn ->
error_check(command, exit_usage())
end) =~ ~r/given:\n\t.*\nUsage:\n.* list_user_permissions/
end) =~ ~r/given:\n\t.*\n\nUsage:\n.* list_user_permissions/
end
test "A bad argument returns a data error" do