| 
									
										
										
										
											2016-02-03 23:01:32 +08:00
										 |  |  | ## The contents of this file are subject to the Mozilla Public License | 
					
						
							|  |  |  | ## Version 1.1 (the "License"); you may not use this file except in | 
					
						
							|  |  |  | ## compliance with the License. You may obtain a copy of the License | 
					
						
							|  |  |  | ## at http://www.mozilla.org/MPL/ | 
					
						
							|  |  |  | ## | 
					
						
							|  |  |  | ## Software distributed under the License is distributed on an "AS IS" | 
					
						
							|  |  |  | ## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | 
					
						
							|  |  |  | ## the License for the specific language governing rights and | 
					
						
							|  |  |  | ## limitations under the License. | 
					
						
							|  |  |  | ## | 
					
						
							|  |  |  | ## The Original Code is RabbitMQ. | 
					
						
							|  |  |  | ## | 
					
						
							|  |  |  | ## The Initial Developer of the Original Code is GoPivotal, Inc. | 
					
						
							|  |  |  | ## Copyright (c) 2007-2016 Pivotal Software, Inc.  All rights reserved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-03 22:42:45 +08:00
										 |  |  | defmodule RabbitMQCtl do | 
					
						
							| 
									
										
										
										
											2016-06-09 09:00:43 +08:00
										 |  |  |   alias RabbitMQ.CLI.Distribution,  as: Distribution | 
					
						
							| 
									
										
										
										
											2016-06-09 08:34:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-10 07:54:22 +08:00
										 |  |  |   alias RabbitMQ.CLI.Ctl.Commands.HelpCommand, as: HelpCommand | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-09 09:08:21 +08:00
										 |  |  |   import RabbitMQ.CLI.Ctl.Helpers | 
					
						
							|  |  |  |   import  RabbitMQ.CLI.Ctl.Parser | 
					
						
							| 
									
										
										
										
											2016-06-09 08:34:56 +08:00
										 |  |  |   import RabbitMQ.CLI.ExitCodes | 
					
						
							| 
									
										
										
										
											2016-02-03 02:54:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-11 01:19:06 +08:00
										 |  |  |   def main(["--auto-complete", "./rabbitmqctl " <> str]) do | 
					
						
							| 
									
										
										
										
											2016-07-29 00:46:37 +08:00
										 |  |  |     auto_complete(str) | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-08-11 01:19:06 +08:00
										 |  |  |   def main(["--auto-complete", "rabbitmqctl " <> str]) do | 
					
						
							| 
									
										
										
										
											2016-07-29 00:46:37 +08:00
										 |  |  |     auto_complete(str) | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-05-09 18:07:46 +08:00
										 |  |  |   def main(unparsed_command) do | 
					
						
							| 
									
										
										
										
											2016-05-27 05:02:10 +08:00
										 |  |  |     {parsed_cmd, options, invalid} = parse(unparsed_command) | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |     {printer, print_options} = get_printer(options) | 
					
						
							|  |  |  |     case try_run_command(parsed_cmd, options, invalid) do | 
					
						
							|  |  |  |       {:validation_failure, _} = invalid -> | 
					
						
							|  |  |  |         error_strings = validation_error(invalid, unparsed_command) | 
					
						
							|  |  |  |         {:error, exit_code_for(invalid), error_strings} | 
					
						
							|  |  |  |       cmd_result -> cmd_result | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     |> print_output(printer, print_options) | 
					
						
							|  |  |  |     |> exit_program | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def get_printer(%{printer: printer} = opts) do | 
					
						
							|  |  |  |     module_name = String.to_atom("RabbitMQ.CLI.Printers." <> | 
					
						
							|  |  |  |                                  Mix.Utils.camelize(printer)) | 
					
						
							|  |  |  |     printer = case Code.ensure_loaded(module_name) do | 
					
						
							|  |  |  |       {:module, _}      -> module_name; | 
					
						
							|  |  |  |       {:error, :nofile} -> default_printer | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     {printer, opts} | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  |   def get_printer(opts) do | 
					
						
							|  |  |  |     {default_printer, opts} | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def default_printer() do | 
					
						
							|  |  |  |     RabbitMQ.CLI.Printers.InspectPrinter | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def print_output({:exit, exit_code, strings}, printer, print_options) do | 
					
						
							|  |  |  |     printer.print_error(Enum.join(strings, "\n"), print_options) | 
					
						
							|  |  |  |     exit_code | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  |   def print_output(:ok, printer, print_options) do | 
					
						
							|  |  |  |     printer.print_ok(print_options) | 
					
						
							|  |  |  |     exit_ok | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  |   def print_output({:ok, single_value}, printer, print_options) do | 
					
						
							|  |  |  |     printer.print_output(single_value, print_options) | 
					
						
							|  |  |  |     exit_ok | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  |   def print_output({:stream, stream}, printer, print_options) do | 
					
						
							|  |  |  |     printer.start_collection(print_options) | 
					
						
							|  |  |  |     exit_code = case print_output_stream(stream, printer, print_options) do | 
					
						
							|  |  |  |       :ok               -> exit_ok; | 
					
						
							|  |  |  |       {:error, _} = err -> exit_code_for(err) | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |     printer.finish_collection(print_options) | 
					
						
							|  |  |  |     exit_code | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def print_output_stream(stream, printer, print_options) do | 
					
						
							|  |  |  |     Enum.reduce_while(stream, :ok, | 
					
						
							|  |  |  |       fn | 
					
						
							|  |  |  |       ({:error, err}, _) -> | 
					
						
							|  |  |  |         printer.print_error(err, print_options) | 
					
						
							|  |  |  |         {:halt, {:error, err}}; | 
					
						
							|  |  |  |       (val, _) -> | 
					
						
							|  |  |  |         printer.print_output(val, print_options) | 
					
						
							|  |  |  |         {:cont, :ok} | 
					
						
							|  |  |  |       end) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   def try_run_command(parsed_cmd, options, invalid) do | 
					
						
							| 
									
										
										
										
											2016-06-09 08:34:56 +08:00
										 |  |  |     case {is_command?(parsed_cmd), invalid} do | 
					
						
							| 
									
										
										
										
											2016-07-29 00:46:37 +08:00
										 |  |  |       ## No such command | 
					
						
							| 
									
										
										
										
											2016-06-08 22:19:37 +08:00
										 |  |  |       {false, _}  -> | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |         {:ok, strings} = HelpCommand.all_usage() | 
					
						
							|  |  |  |         {:error, exit_usage, strings}; | 
					
						
							| 
									
										
										
										
											2016-07-29 00:46:37 +08:00
										 |  |  |       ## Invalid options | 
					
						
							| 
									
										
										
										
											2016-06-08 22:19:37 +08:00
										 |  |  |       {_, [_|_]}  -> | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |         {:validation_failure, {:bad_option, invalid}}; | 
					
						
							| 
									
										
										
										
											2016-07-29 00:46:37 +08:00
										 |  |  |       ## Command valid | 
					
						
							| 
									
										
										
										
											2016-06-08 22:19:37 +08:00
										 |  |  |       {true, []}  -> | 
					
						
							| 
									
										
										
										
											2016-08-09 02:43:09 +08:00
										 |  |  |         effective_options = options |> merge_all_defaults |> normalize_node | 
					
						
							| 
									
										
										
										
											2016-06-09 08:34:56 +08:00
										 |  |  |         Distribution.start(effective_options) | 
					
						
							| 
									
										
										
										
											2016-06-08 22:19:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |         run_command(effective_options, parsed_cmd) | 
					
						
							| 
									
										
										
										
											2016-03-05 05:35:54 +08:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-02-03 05:32:35 +08:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-29 00:46:37 +08:00
										 |  |  |   def auto_complete(str) do | 
					
						
							|  |  |  |     AutoComplete.complete(str) | 
					
						
							|  |  |  |     |> Stream.map(&IO.puts/1) |> Stream.run | 
					
						
							|  |  |  |     exit_program(exit_ok) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-09 02:43:09 +08:00
										 |  |  |   def merge_all_defaults(%{} = options) do | 
					
						
							| 
									
										
										
										
											2016-03-08 03:08:38 +08:00
										 |  |  |     options | 
					
						
							| 
									
										
										
										
											2016-05-24 19:33:11 +08:00
										 |  |  |     |> merge_defaults_node | 
					
						
							|  |  |  |     |> merge_defaults_timeout | 
					
						
							| 
									
										
										
										
											2016-06-08 22:19:37 +08:00
										 |  |  |     |> merge_defaults_longnames | 
					
						
							| 
									
										
										
										
											2016-03-08 03:08:38 +08:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 19:33:11 +08:00
										 |  |  |   defp merge_defaults_node(%{} = opts), do: Map.merge(%{node: get_rabbit_hostname}, opts) | 
					
						
							| 
									
										
										
										
											2016-03-08 06:45:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 19:33:11 +08:00
										 |  |  |   defp merge_defaults_timeout(%{} = opts), do: Map.merge(%{timeout: :infinity}, opts) | 
					
						
							| 
									
										
										
										
											2016-03-08 06:45:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-08 22:19:37 +08:00
										 |  |  |   defp merge_defaults_longnames(%{} = opts), do: Map.merge(%{longnames: false}, opts) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-10 05:55:59 +08:00
										 |  |  |   defp normalize_node(%{node: node} = opts) do | 
					
						
							|  |  |  |     Map.merge(opts, %{node: parse_node(node)}) | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 06:38:09 +08:00
										 |  |  |   defp maybe_connect_to_rabbitmq("help", _), do: nil | 
					
						
							| 
									
										
										
										
											2016-05-31 16:40:48 +08:00
										 |  |  |   defp maybe_connect_to_rabbitmq(_, node) do | 
					
						
							| 
									
										
										
										
											2016-06-09 08:34:56 +08:00
										 |  |  |     connect_to_rabbitmq(node) | 
					
						
							| 
									
										
										
										
											2016-05-31 16:40:48 +08:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 07:04:24 +08:00
										 |  |  |   defp run_command(_, []), do: HelpCommand.all_usage() | 
					
						
							| 
									
										
										
										
											2016-05-06 01:17:50 +08:00
										 |  |  |   defp run_command(options, [command_name | arguments]) do | 
					
						
							| 
									
										
										
										
											2016-05-09 18:07:46 +08:00
										 |  |  |     with_command(command_name, | 
					
						
							|  |  |  |         fn(command) -> | 
					
						
							|  |  |  |             case invalid_flags(command, options) do | 
					
						
							| 
									
										
										
										
											2016-05-26 07:04:24 +08:00
										 |  |  |               [] -> | 
					
						
							| 
									
										
										
										
											2016-08-12 09:36:51 +08:00
										 |  |  |                 {arguments, options} = command.merge_defaults(arguments, options) | 
					
						
							| 
									
										
										
										
											2016-05-24 19:33:11 +08:00
										 |  |  |                 case command.validate(arguments, options) do | 
					
						
							|  |  |  |                   :ok -> | 
					
						
							|  |  |  |                     print_banner(command, arguments, options) | 
					
						
							| 
									
										
										
										
											2016-05-31 16:40:48 +08:00
										 |  |  |                     maybe_connect_to_rabbitmq(command_name, options[:node]) | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     command.run(arguments, options) | 
					
						
							|  |  |  |                     |> command.output(options) | 
					
						
							| 
									
										
										
										
											2016-05-24 19:33:11 +08:00
										 |  |  |                   err -> err | 
					
						
							|  |  |  |                 end | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |               result  -> {:validation_failure, {:bad_option, result}} | 
					
						
							| 
									
										
										
										
											2016-05-09 18:07:46 +08:00
										 |  |  |             end | 
					
						
							|  |  |  |         end) | 
					
						
							| 
									
										
										
										
											2016-02-03 02:54:36 +08:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-02-26 05:16:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-09 18:07:46 +08:00
										 |  |  |   defp with_command(command_name, fun) do | 
					
						
							| 
									
										
										
										
											2016-06-09 08:34:56 +08:00
										 |  |  |     command = commands[command_name] | 
					
						
							| 
									
										
										
										
											2016-05-26 07:04:24 +08:00
										 |  |  |     fun.(command) | 
					
						
							| 
									
										
										
										
											2016-05-05 06:31:11 +08:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-04-27 02:38:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 19:33:11 +08:00
										 |  |  |   defp print_banner(command, args, opts) do | 
					
						
							| 
									
										
										
										
											2016-05-31 16:40:48 +08:00
										 |  |  |     case command.banner(args, opts) do | 
					
						
							| 
									
										
										
										
											2016-06-02 06:38:09 +08:00
										 |  |  |      nil -> nil | 
					
						
							| 
									
										
										
										
											2016-05-31 16:40:48 +08:00
										 |  |  |      banner -> IO.inspect banner | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-05-24 19:33:11 +08:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 02:38:23 +08:00
										 |  |  |   defp print_standard_messages({:refused, user, _, _} = result, _) do | 
					
						
							| 
									
										
										
										
											2016-04-02 01:58:47 +08:00
										 |  |  |     IO.puts "Error: failed to authenticate user \"#{user}\"" | 
					
						
							| 
									
										
										
										
											2016-04-27 02:38:23 +08:00
										 |  |  |     result | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 22:02:58 +08:00
										 |  |  |   defp print_standard_messages( | 
					
						
							|  |  |  |     {failed_command, | 
					
						
							|  |  |  |      {:mnesia_unexpectedly_running, node_name}} = result, _) | 
					
						
							|  |  |  |   when | 
					
						
							|  |  |  |     failed_command == :reset_failed or | 
					
						
							| 
									
										
										
										
											2016-07-27 01:08:37 +08:00
										 |  |  |     failed_command == :join_cluster_failed or | 
					
						
							| 
									
										
										
										
											2016-08-12 09:36:51 +08:00
										 |  |  |     failed_command == :rename_node_failed or | 
					
						
							| 
									
										
										
										
											2016-07-25 23:48:45 +08:00
										 |  |  |     failed_command == :change_node_type_failed | 
					
						
							| 
									
										
										
										
											2016-06-06 22:02:58 +08:00
										 |  |  |   do | 
					
						
							| 
									
										
										
										
											2016-06-02 18:19:07 +08:00
										 |  |  |     IO.puts "Mnesia is still running on node #{node_name}." | 
					
						
							| 
									
										
										
										
											2016-06-06 22:00:50 +08:00
										 |  |  |     IO.puts "Please stop RabbitMQ with rabbitmqctl stop_app first." | 
					
						
							| 
									
										
										
										
											2016-06-02 18:19:07 +08:00
										 |  |  |     result | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 22:36:52 +08:00
										 |  |  |   defp print_standard_messages({:error, :process_not_running} = result, _) do | 
					
						
							|  |  |  |     IO.puts "Error: process is not running." | 
					
						
							|  |  |  |     result | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   defp print_standard_messages({:error, {:garbage_in_pid_file, _}} = result, _) do | 
					
						
							|  |  |  |     IO.puts "Error: garbage in pid file." | 
					
						
							|  |  |  |     result | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   defp print_standard_messages({:error, {:could_not_read_pid, err}} = result, _) do | 
					
						
							|  |  |  |     IO.puts "Error: could not read pid. Detail: #{err}" | 
					
						
							|  |  |  |     result | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 06:38:09 +08:00
										 |  |  |   defp print_standard_messages({:healthcheck_failed, message} = result, _) do | 
					
						
							|  |  |  |     IO.puts "Error: healthcheck failed. Message: #{message}" | 
					
						
							|  |  |  |     result | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |   defp validation_error({:validation_failure, err_detail}, unparsed_command) do | 
					
						
							| 
									
										
										
										
											2016-05-30 07:16:10 +08:00
										 |  |  |     {[command_name | _], _, _} = parse(unparsed_command) | 
					
						
							|  |  |  |     err = format_validation_error(err_detail) # TODO format the error better | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |     base_error = ["Error: #{err}", "Given:\n\t#{unparsed_command |> Enum.join(" ")}"] | 
					
						
							| 
									
										
										
										
											2016-05-30 07:16:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-09 08:34:56 +08:00
										 |  |  |     case is_command?(command_name) do | 
					
						
							| 
									
										
										
										
											2016-05-30 07:16:10 +08:00
										 |  |  |       true  -> | 
					
						
							| 
									
										
										
										
											2016-06-09 08:34:56 +08:00
										 |  |  |         command = commands[command_name] | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |         base_error ++ HelpCommand.print_base_usage(HelpCommand.program_name(), command) | 
					
						
							| 
									
										
										
										
											2016-05-30 07:16:10 +08:00
										 |  |  |       false -> | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |         base_error ++ HelpCommand.all_usage() | 
					
						
							| 
									
										
										
										
											2016-05-30 07:16:10 +08:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-04-02 01:58:47 +08:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 19:33:11 +08:00
										 |  |  |   defp format_validation_error(:not_enough_args), do: "not enough arguments." | 
					
						
							|  |  |  |   defp format_validation_error({:not_enough_args, detail}), do: "not enough arguments. #{detail}" | 
					
						
							|  |  |  |   defp format_validation_error(:too_many_args), do: "too many arguments." | 
					
						
							|  |  |  |   defp format_validation_error({:too_many_args, detail}), do: "too many arguments. #{detail}" | 
					
						
							|  |  |  |   defp format_validation_error(:bad_argument), do: "Bad argument." | 
					
						
							|  |  |  |   defp format_validation_error({:bad_argument, detail}), do: "Bad argument. #{detail}" | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |   defp format_validation_error({:bad_option, opts}) do | 
					
						
							|  |  |  |     Enum.join(["Invalid options:" | for {key, val} <- opts do "#{key} : #{val}" end], "\n") | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-05-24 19:33:11 +08:00
										 |  |  |   defp format_validation_error(err), do: inspect err | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |   # defp handle_exit(true), do: handle_exit(:ok, exit_ok) | 
					
						
							|  |  |  |   # defp handle_exit(:ok), do: handle_exit(:ok, exit_ok) | 
					
						
							|  |  |  |   # defp handle_exit({:ok, result}), do: handle_exit({:ok, result}, exit_ok) | 
					
						
							|  |  |  |   # defp handle_exit(result) when is_list(result), do: handle_exit({:ok, result}, exit_ok) | 
					
						
							|  |  |  |   # defp handle_exit(:ok, code), do: exit_program(code) | 
					
						
							|  |  |  |   # defp handle_exit({:ok, result}, code) do | 
					
						
							|  |  |  |   #   case Enumerable.impl_for(result) do | 
					
						
							|  |  |  |   #     nil -> IO.inspect result; | 
					
						
							|  |  |  |   #     _   -> result |> Stream.map(&IO.inspect/1) |> Stream.run | 
					
						
							|  |  |  |   #   end | 
					
						
							|  |  |  |   #   exit_program(code) | 
					
						
							|  |  |  |   # end | 
					
						
							| 
									
										
										
										
											2016-03-23 00:21:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-05 18:39:27 +08:00
										 |  |  |   defp invalid_flags(command, opts) do | 
					
						
							| 
									
										
										
										
											2016-08-18 21:56:21 +08:00
										 |  |  |     Map.take(opts, Map.keys(opts) -- (command.flags ++ global_flags)) | 
					
						
							|  |  |  |     |> Map.to_list | 
					
						
							| 
									
										
										
										
											2016-05-05 03:40:09 +08:00
										 |  |  |   end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-23 00:21:12 +08:00
										 |  |  |   defp exit_program(code) do | 
					
						
							|  |  |  |     :net_kernel.stop | 
					
						
							| 
									
										
										
										
											2016-04-02 00:13:01 +08:00
										 |  |  |     exit({:shutdown, code}) | 
					
						
							| 
									
										
										
										
											2016-03-23 00:21:12 +08:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2016-02-03 02:54:36 +08:00
										 |  |  | end |