Changed script file parsing
[makerl.git] / src / mkrl_os_shell.erl
bloba51fccc4fadcda1a64a56714a5f279139d24c0a7
1 %%%-------------------------------------------------------------------
2 %%% File : os_shell.erl
3 %%% Author : <>
4 %%% Description : Module abstracting os shell
5 %%%
6 %%% Created : 22 Mar 2011 by <>
7 %%%-------------------------------------------------------------------
8 -module(mkrl_os_shell).
9 -include("makerl.hrl").
10 -compile(export_all).
12 os_filter_cmd(Cmd) ->
13 case os:type() of
14 {win32, _ } ->
15 "cmd /C " ++ Cmd;
16 _ -> Cmd %% Bash o algo? usar os:find_executable?
17 end.
19 cmd(Command) ->
20 sh(os_filter_cmd(Command)).
21 cmd(Command, Opts) ->
22 sh(os_filter_cmd(Command), Opts).
24 sh(Command) ->
25 sh(Command, []).
27 %% Options = [Option] -- defaults to [use_stdout, abort_on_error]
28 %% Option = ErrorOption | OutputOption | {cd, string()} | {env, Env}
29 %% ErrorOption = return_on_error | abort_on_error | {abort_on_error, string()}
30 %% OutputOption = use_stdout | {use_stdout, bool()}
31 %% Env = [{string(), Val}]
32 %% Val = string() | false
34 sh(Command, Options0) ->
35 ?INFO("sh: ~s\n~p\n", [Command, Options0]),
37 DefaultOptions = [use_stdout, abort_on_error],
38 Options = lists:map(fun expand_sh_flag/1,
39 proplists:compact(Options0 ++ DefaultOptions)),
41 ErrorHandler = proplists:get_value(error_handler, Options),
42 OutputHandler = proplists:get_value(output_handler, Options),
44 PortSettings = proplists:get_all_values(port_settings, Options) ++
45 [exit_status, {line, 16384}, use_stdio, stderr_to_stdout, hide],
46 Port = open_port({spawn, Command}, PortSettings),
48 case sh_loop(Port, OutputHandler, []) of
49 {ok, Output} ->
50 {ok, Output};
51 {error, Rc} ->
52 ErrorHandler(Command, Rc)
53 end.
56 %% expand_sh_flag
58 expand_sh_flag(return_on_error) ->
59 {error_handler,
60 fun(_Command, Rc) ->
61 {error, Rc}
62 end};
63 expand_sh_flag({abort_on_error, Message}) ->
64 {error_handler,
65 log_and_abort(Message)};
66 expand_sh_flag(abort_on_error) ->
67 {error_handler,
68 fun log_w_rc_and_abort/2};
69 expand_sh_flag(use_stdout) ->
70 {output_handler,
71 fun(Line, Acc) ->
72 ?CONSOLE("~s", [Line]),
73 [Acc | Line]
74 end};
75 expand_sh_flag({use_stdout, false}) ->
76 {output_handler,
77 fun(Line, Acc) ->
78 [Acc | Line]
79 end};
80 expand_sh_flag({cd, Dir}) ->
81 {port_settings, {cd, Dir}};
82 expand_sh_flag({env, Env}) ->
83 {port_settings, {env, Env}}.
86 -spec log_and_abort(string()) -> fun((string(), integer()) -> no_return()).
87 log_and_abort(Message) ->
88 fun(_, _) ->
89 ?ERROR(Message, []),
90 ?FAIL
91 end.
93 -spec log_w_rc_and_abort(string(), integer()) -> no_return().
94 log_w_rc_and_abort(Command, Rc) ->
95 ?ERROR("~s failed with error: ~w\n", [Command, Rc]),
96 ?FAIL.
98 sh_loop(Port, Fun, Acc) ->
99 receive
100 {Port, {data, {_, "_port_cmd_status_ " ++ Status}}} ->
101 (catch erlang:port_close(Port)), % sigh () for indentation
102 case list_to_integer(Status) of
103 0 -> {ok, lists:flatten(Acc)};
104 Rc -> {error, Rc}
105 end;
106 {Port, {data, {eol, Line}}} ->
107 sh_loop(Port, Fun, Fun(Line ++ "\n", Acc));
108 {Port, {data, {noeol, Line}}} ->
109 sh_loop(Port, Fun, Fun(Line, Acc));
110 {Port, {exit_status, 0}} ->
111 {ok, lists:flatten(Acc)};
112 {Port, {exit_status, Rc}} ->
113 {error, Rc}
114 end.