Skip to content
This repository has been archived by the owner on Nov 18, 2020. It is now read-only.

Commit

Permalink
Merge pull request #179 from rabbitmq/rabbitmq-cli-178
Browse files Browse the repository at this point in the history
Implement `rabbitmqctl hipe_compile`
  • Loading branch information
hairyhum committed Mar 14, 2017
2 parents 1d17ae3 + d0cb138 commit fb5be56
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 21 deletions.
2 changes: 1 addition & 1 deletion lib/rabbitmq/cli/core/command_modules.ex
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ defmodule RabbitMQ.CLI.Core.CommandModules do
end

def ctl_and_plugin_modules(opts) do
Helpers.require_rabbit(opts)
Helpers.require_rabbit_and_plugins(opts)
enabled_plugins = PluginsHelpers.read_enabled(opts)
[:rabbitmqctl | enabled_plugins]
|> Enum.flat_map(fn(app) -> Application.spec(app, :modules) || [] end)
Expand Down
1 change: 1 addition & 0 deletions lib/rabbitmq/cli/core/exit_codes.ex
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ defmodule RabbitMQ.CLI.Core.ExitCodes do
def exit_code_for({:validation_failure, {:too_many_args, _}}), do: exit_usage()
def exit_code_for({:validation_failure, {:bad_argument, _}}), do: exit_dataerr()
def exit_code_for({:validation_failure, :bad_argument}), do: exit_dataerr()
def exit_code_for({:validation_failure, :eperm}), do: exit_dataerr()
def exit_code_for({:validation_failure, {:bad_option, _}}), do: exit_usage()
def exit_code_for({:validation_failure, _}), do: exit_usage()
def exit_code_for({:badrpc, :timeout}), do: exit_tempfail()
Expand Down
14 changes: 14 additions & 0 deletions lib/rabbitmq/cli/core/helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ defmodule RabbitMQ.CLI.Core.Helpers do

def hostname, do: :inet.gethostname() |> elem(1) |> List.to_string

def validate_step(:ok, step) do
case step.() do
{:error, err} -> {:validation_failure, err};
_ -> :ok
end
end
def validate_step({:validation_failure, err}, _) do
{:validation_failure, err}
end

def memory_units do
["k", "kiB", "M", "MiB", "G", "GiB", "kB", "MB", "GB", ""]
end
Expand Down Expand Up @@ -88,6 +98,10 @@ defmodule RabbitMQ.CLI.Core.Helpers do
end

def require_rabbit(opts) do
try_load_rabbit_code(opts)
end

def require_rabbit_and_plugins(opts) do
with :ok <- try_load_rabbit_code(opts),
:ok <- try_load_rabbit_plugins(opts),
do: :ok
Expand Down
88 changes: 88 additions & 0 deletions lib/rabbitmq/cli/ctl/commands/hipe_compile_command.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
## 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 Pivotal Software, Inc.
## Copyright (c) 2016-2017 Pivotal Software, Inc. All rights reserved.

defmodule RabbitMQ.CLI.Ctl.Commands.HipeCompileCommand do
alias RabbitMQ.CLI.Core.Helpers, as: Helpers

@behaviour RabbitMQ.CLI.CommandBehaviour
use RabbitMQ.CLI.DefaultOutput

#
# API
#

def merge_defaults(args, opts) do
{args, opts}
end

def switches(), do: [rabbitmq_home: :string]

def usage, do: "hipe_compile <directory>"

def validate([], _), do: {:validation_failure, :not_enough_args}
def validate([target_dir], opts) do
:ok
|> Helpers.validate_step(fn() ->
case acceptable_path?(target_dir) do
true -> :ok
false -> {:error, {:bad_argument, "Target directory path cannot be blank"}}
end
end)
|> Helpers.validate_step(fn() ->
case File.dir?(target_dir) do
true -> :ok
false ->
case File.mkdir_p(target_dir) do
:ok -> :ok
{:error, :eperm} ->
{:error, {:bad_argument, "Cannot create target directory #{target_dir}: insufficient permissions"}}
end
end
end)
|> Helpers.validate_step(fn() -> Helpers.require_rabbit(opts) end)
end
def validate(_, _), do: {:validation_failure, :too_many_args}

def run([target_dir], _opts) do
Code.ensure_loaded(:rabbit_hipe)
hipe_compile(String.trim(target_dir))
end

def banner([target_dir], _) do
"Will pre-compile RabbitMQ server modules with HiPE to #{target_dir} ..."
end

#
# Implementation
#

# Accepts any non-blank path
defp acceptable_path?(value) do
String.length(String.trim(value)) != 0
end

defp hipe_compile(target_dir) do
case :rabbit_hipe.can_hipe_compile() do
true ->
case :rabbit_hipe.compile_to_directory(target_dir) do
{:ok, _, _} -> :ok
{:ok, :already_compiled} -> {:ok, "already compiled"}
{:error, message} -> {:error, message}
end
false ->
{:error, "HiPE compilation is not supported"}
end
end
end
1 change: 0 additions & 1 deletion lib/rabbitmq/cli/ctl/validators.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,4 @@ defmodule RabbitMQ.CLI.Ctl.Validators do
{:error, err} -> {:validation_failure, err}
end
end

end
2 changes: 1 addition & 1 deletion lib/rabbitmq/cli/plugins/commands/disable_command.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ defmodule RabbitMQ.CLI.Plugins.Commands.DisableCommand do

def validate(_, opts) do
:ok
|> validate_step(fn() -> Helpers.require_rabbit(opts) end)
|> validate_step(fn() -> Helpers.require_rabbit_and_plugins(opts) end)
|> validate_step(fn() -> PluginHelpers.enabled_plugins_file(opts) end)
|> validate_step(fn() -> Helpers.plugins_dir(opts) end)
end
Expand Down
16 changes: 3 additions & 13 deletions lib/rabbitmq/cli/plugins/commands/enable_command.ex
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,9 @@ defmodule RabbitMQ.CLI.Plugins.Commands.EnableCommand do

def validate(_plugins, opts) do
:ok
|> validate_step(fn() -> Helpers.require_rabbit(opts) end)
|> validate_step(fn() -> PluginHelpers.enabled_plugins_file(opts) end)
|> validate_step(fn() -> Helpers.plugins_dir(opts) end)
end

def validate_step(:ok, step) do
case step.() do
{:error, err} -> {:validation_failure, err};
_ -> :ok
end
end
def validate_step({:validation_failure, err}, _) do
{:validation_failure, err}
|> Helpers.validate_step(fn() -> Helpers.require_rabbit_and_plugins(opts) end)
|> Helpers.validate_step(fn() -> PluginHelpers.enabled_plugins_file(opts) end)
|> Helpers.validate_step(fn() -> Helpers.plugins_dir(opts) end)
end

def usage, do: "enable <plugin>|--all [--offline] [--online]"
Expand Down
2 changes: 1 addition & 1 deletion lib/rabbitmq/cli/plugins/commands/list_command.ex
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ defmodule RabbitMQ.CLI.Plugins.Commands.ListCommand do

def validate(_, opts) do
:ok
|> validate_step(fn() -> Helpers.require_rabbit(opts) end)
|> validate_step(fn() -> Helpers.require_rabbit_and_plugins(opts) end)
|> validate_step(fn() -> PluginHelpers.enabled_plugins_file(opts) end)
|> validate_step(fn() -> Helpers.plugins_dir(opts) end)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rabbitmq/cli/plugins/commands/set_command.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ defmodule RabbitMQ.CLI.Plugins.Commands.SetCommand do

def validate(_plugins, opts) do
:ok
|> validate_step(fn() -> Helpers.require_rabbit(opts) end)
|> validate_step(fn() -> Helpers.require_rabbit_and_plugins(opts) end)
|> validate_step(fn() -> PluginHelpers.enabled_plugins_file(opts) end)
|> validate_step(fn() -> Helpers.plugins_dir(opts) end)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rabbitmq/cli/plugins/plugins_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ defmodule RabbitMQ.CLI.Plugins.Helpers do

def set_enabled_plugins(plugins, opts) do
plugin_atoms = :lists.usort(for plugin <- plugins, do: to_atom(plugin))
CliHelpers.require_rabbit(opts)
CliHelpers.require_rabbit_and_plugins(opts)
{:ok, plugins_file} = enabled_plugins_file(opts)
write_enabled_plugins(plugin_atoms, plugins_file, opts)
end
Expand Down
1 change: 1 addition & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ defmodule RabbitMQCtl.MixfileBase do
override: true
},
{:amqp, "~> 0.1.5", only: :test},
{:temp, "~> 0.4", only: :test},
{:json, "~> 1.0.0"},
{:csv, "~> 1.4.2"},
{:simetric, "~> 0.1.0"}
Expand Down
4 changes: 2 additions & 2 deletions test/core/helpers_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ test "RabbitMQ hostname is properly formed" do
opts = %{plugins_dir: to_string(plugins_directory_03),
rabbitmq_home: rabbitmq_home}
assert Enum.member?(Application.loaded_applications(), {:mock_rabbitmq_plugins_03, 'New project', '0.1.0'}) == false
@subject.require_rabbit(opts)
@subject.require_rabbit_and_plugins(opts)
assert Enum.member?(Application.loaded_applications(), {:mock_rabbitmq_plugins_03, 'New project', '0.1.0'})
end

Expand All @@ -134,7 +134,7 @@ test "RabbitMQ hostname is properly formed" do
opts = %{plugins_dir: to_string(plugins_directory_04),
rabbitmq_home: rabbitmq_home}
assert Enum.member?(Application.loaded_applications(), {:mock_rabbitmq_plugins_04, 'New project', 'rolling'}) == false
@subject.require_rabbit(opts)
@subject.require_rabbit_and_plugins(opts)
assert Enum.member?(Application.loaded_applications(), {:mock_rabbitmq_plugins_04, 'New project', 'rolling'})
end

Expand Down
81 changes: 81 additions & 0 deletions test/hipe_compile_command_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
## 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 Pivotal Software, Inc.
## Copyright (c) 2016-2017 Pivotal Software, Inc. All rights reserved.

defmodule HipeCompileCommandTest do
use ExUnit.Case, async: false
import TestHelper

require Temp

@command RabbitMQ.CLI.Ctl.Commands.HipeCompileCommand
@vhost "/"

setup_all do
RabbitMQ.CLI.Core.Distribution.start()
:net_kernel.connect_node(get_rabbit_hostname())

start_rabbitmq_app()

on_exit([], fn ->
:erlang.disconnect_node(get_rabbit_hostname())
end)
end

setup do
rabbitmq_home = :rabbit_misc.rpc_call(node(), :code, :lib_dir, [:rabbit])

{:ok, tmp_dir} = Temp.path

{:ok, opts: %{
node: get_rabbit_hostname(),
vhost: @vhost,
rabbitmq_home: rabbitmq_home
},
target_dir: tmp_dir
}
end

test "validate: providing no arguments fails validation", context do
assert @command.validate([], context[:opts]) ==
{:validation_failure, :not_enough_args}
end

test "validate: providing two arguments fails validation", context do
assert @command.validate(["/path/one", "/path/two"], context[:opts]) ==
{:validation_failure, :too_many_args}
end

test "validate: providing three arguments fails validation", context do
assert @command.validate(["/path/one", "/path/two", "/path/three"], context[:opts]) ==
{:validation_failure, :too_many_args}
end

test "validate: providing one blank directory path and required options fails", context do
assert match?({:validation_failure, {:bad_argument, _}}, @command.validate([""], context[:opts]))
end

test "validate: providing one path argument that only contains spaces and required options fails", context do
assert match?({:validation_failure, {:bad_argument, _}}, @command.validate([" "], context[:opts]))
end

test "validate: providing one non-blank directory path and required options succeeds", context do
assert @command.validate([context[:target_dir]], context[:opts]) == :ok
end

test "validate: failure to load the rabbit application is reported as an error", context do
assert {:validation_failure, {:unable_to_load_rabbit, _}} =
@command.validate([context[:target_dir]], Map.delete(context[:opts], :rabbitmq_home))
end
end

0 comments on commit fb5be56

Please sign in to comment.