Packages

Erlang libvirt remote protocol

Current section

Files

Jump to
verx bin mk_verx.escript
Raw

bin/mk_verx.escript

#!/usr/bin/env escript
%%%
%%% Generate the verx.erl file
%%%
main(_) ->
% load remote_protocol_xdr
Path = os:getenv("REBAR_BUILD_DIR", filename:join(
filename:dirname(escript:script_name()),
"../_build/default"
)),
true = code:add_pathz(filename:join(Path, "lib/verx/ebin")),
{module, remote_protocol_xdr} = code:load_file(remote_protocol_xdr),
{{Year,_,_},{_,_,_}} = calendar:universal_time(),
Date = integer_to_list(Year),
Comment = [
" Copyright (c) 2011-" ++ Date ++ ", Michael Santos <michael.santos@gmail.com>",
" All rights reserved.",
"",
" Redistribution and use in source and binary forms, with or without",
" modification, are permitted provided that the following conditions",
" are met:",
"",
" Redistributions of source code must retain the above copyright",
" notice, this list of conditions and the following disclaimer.",
"",
" Redistributions in binary form must reproduce the above copyright",
" notice, this list of conditions and the following disclaimer in the",
" documentation and/or other materials provided with the distribution.",
"",
" Neither the name of the author nor the names of its contributors",
" may be used to endorse or promote products derived from this software",
" without specific prior written permission.",
"",
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS",
" \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT",
" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS",
" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE",
" COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,",
" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,",
" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;",
" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER",
" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT",
" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN",
" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE",
" POSSIBILITY OF SUCH DAMAGE."],
License = erl_syntax:comment(Comment),
Module = erl_syntax:attribute(
erl_syntax:atom(module),
[erl_syntax:atom("verx")]
),
Includes = includes(["verx.hrl"]),
% Any hardcoded functions will be included here
Static = erl_syntax:comment(["%__STATIC__%%"]),
Calls = calls(),
% Generate the list of exports
Comment_static = erl_syntax:comment([" Static functions"]),
Exports_static = erl_syntax:attribute(erl_syntax:atom(export), [
erl_syntax:list([
erl_syntax:arity_qualifier(erl_syntax:atom(Fun), erl_syntax:integer(Arity))
|| {Fun, Arity} <- static_exports() ])
]),
Comment_gen = erl_syntax:comment([" Generated functions"]),
Exports_gen = erl_syntax:attribute(erl_syntax:atom(export), [
erl_syntax:list([
erl_syntax:arity_qualifier(erl_syntax:atom(Fun), erl_syntax:integer(Arity+1))
|| {Fun, _, Arity} <- Calls ])
]),
% Generate the functions
Functions = [ begin
{Pattern, Body} = case Arity of
0 ->
% name(Ref) -> verx_client:call(Ref, 'PROC_NAME').
{[erl_syntax:variable("Ref")],
erl_syntax:application(
erl_syntax:atom(verx_client),
erl_syntax:atom(call),
[erl_syntax:variable("Ref"), erl_syntax:atom(Proc)]
)};
_ ->
% name(Ref, Arg) -> verx_client:call(Ref, 'PROC_NAME', Arg).
{[erl_syntax:variable("Ref"), erl_syntax:variable("Arg")],
erl_syntax:application(
erl_syntax:atom(verx_client),
erl_syntax:atom(call),
[erl_syntax:variable("Ref"), erl_syntax:atom(Proc),
erl_syntax:variable("Arg")]
)}
end,
Clause = erl_syntax:clause(Pattern, [], [Body]),
erl_syntax:function(erl_syntax:atom(Fun), [Clause])
end || {Fun, Proc, Arity} <- Calls ],
Code0 = erl_prettypr:format(erl_syntax:form_list(lists:flatten([
License,
Module,
Includes,
Comment_static,
Exports_static,
Comment_gen,
Exports_gen,
Static,
Functions
]))),
Code = re:replace(Code0, "%%__STATIC__%%", static()),
io:format("~s~n", [Code]).
% List the supported libvirt remote protocol procedures
calls() ->
% count from 1 until an exception is thrown
calls(1, []).
calls(N, Acc) ->
try remote_protocol_xdr:dec_remote_procedure(<<N:32>>, 0) of
{Proc, _Off} -> calls(N+1, [Proc|Acc])
catch
error:{case_clause,_} ->
call_to_fun(lists:reverse(Acc))
end.
call_to_fun(Calls) ->
Exports = proplists:get_value(exports, remote_protocol_xdr:module_info()),
[ begin
"remote_proc_" ++ Name = string:to_lower(atom_to_list(N)),
{
Name, % function name
N, % remote protocol procedure
call_arity(Name, Exports) % number of arguments
}
end || N <- Calls ].
call_arity(Proc, Exports) ->
Fun = list_to_atom("enc_remote_" ++ Proc ++ "_args"),
proplists:get_value(Fun, Exports, 0).
static_exports() ->
[{connect_open, 1}, {open, 1}, {open, 2},
{close, 1},
{lookup, 2}].
static() ->
[ static({Fun, Arity}) || {Fun, Arity} <- static_exports() ].
static({connect_open, 1}) ->
"
% Send a remote protocol open message
% <<>> : name
% 0 : flags
% See: remote_protocol_xdr:enc_remote_connect_open_args/1
connect_open(Ref) ->
connect_open(Ref, [<<>>, 0]).
";
static({open, 1}) ->
"
% For backwards compatibility, use connect_open/1,2.
open(Ref) ->
connect_open(Ref, [<<>>, 0]).
";
static({open, 2}) ->
"
open(Ref, Arg) ->
connect_open(Ref, Arg).
";
static({close, 1}) ->
"
close(Ref) ->
connect_close(Ref).
";
static({lookup, 2}) ->
"
lookup(Ref, {domain, Name}) ->
Fun = [ fun() -> verx:domain_lookup_by_id(Ref, [maybe_integer(Name)]) end,
fun() -> verx:domain_lookup_by_name(Ref, [maybe_binary(Name)]) end,
fun() -> verx:domain_lookup_by_uuid(Ref, [uuid:string_to_uuid(Name)]) end,
fun() -> verx:domain_lookup_by_uuid(Ref, [maybe_binary(Name)]) end ],
lookup_1(Fun).
lookup_1(Fun) ->
lookup_1(Fun, []).
lookup_1([], [{error, Error}|_]) ->
{error, Error};
lookup_1([Fun|Tail], Acc) ->
try Fun() of
{ok, Res} ->
{ok, Res};
{error, Error} ->
lookup_1(Tail, [{error, Error}|Acc])
catch
_:_ ->
lookup_1(Tail, Acc)
end.
maybe_integer(N) when is_integer(N) -> N;
maybe_integer(N) when is_list(N) -> list_to_integer(N).
maybe_binary(N) when is_binary(N) -> N;
maybe_binary(N) when is_list(N) -> list_to_binary(N).
".
includes(Header) ->
[ erl_syntax:attribute(erl_syntax:atom(include), [erl_syntax:string(N)]) || N <- Header ].