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

Implement rabbitmqctl hipe_compile #179

Merged
merged 5 commits into from
Mar 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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