Current section
Files
Jump to
Current section
Files
src/vsn_transform.erl
-module(vsn_transform).
-export([parse_transform/2]).
parse_transform(Forms, Options) ->
parse_transform(Forms,
proplists:get_value(vsn, Options, undefined),
proplists:get_value(vsn_command, Options, undefined)).
parse_transform(Forms, undefined, undefined) ->
Forms;
parse_transform(Forms, Vsn, undefined) ->
apply_vsn(Forms, ensure_string(Vsn));
parse_transform(Forms, undefined, Command) ->
Output = os:cmd(ensure_string(Command)),
Vsn = strip_trailing_whitespace(Output),
apply_vsn(Forms, Vsn);
parse_transform(_Forms, _, _) ->
error(both_vsn_and_command).
apply_vsn(Forms, Vsn) ->
HasVsn = lists:any(
fun({attribute, _, vsn, _V}) ->
true;
(_) -> false
end, Forms),
% Lie about the line number, so we don't offset everything else.
Line = 1,
VsnAttr = {attribute, Line, vsn, Vsn},
apply_vsn(HasVsn, VsnAttr, Forms).
apply_vsn(true, _VsnAttr, Forms) ->
Forms;
apply_vsn(false, VsnAttr,
[{attribute, _, file, _F} = FileAttr,
{attribute, _, module, _M} = ModuleAttr | Rest]) ->
% We know that file and module have to come first; we want to insert
% immediately afterwards, so we can get away with this:
[FileAttr, ModuleAttr, VsnAttr | Rest];
apply_vsn(false, _VsnAttr, _Forms) ->
% Does your source file have a module attribute?
error(no_module_attribute).
strip_trailing_whitespace(S) ->
re:replace(S, "[ \t\n]+$", "", [global, {return, list}]).
ensure_string(S) when is_list(S) -> S;
ensure_string(S) when is_binary(S) -> binary_to_list(S).