diff options
author | Lukas Larsson <[email protected]> | 2017-12-13 11:22:45 +0100 |
---|---|---|
committer | Sverker Eriksson <[email protected]> | 2018-03-21 17:51:57 +0100 |
commit | b6df9b6babb5002c5eb940e27474855abf4c5930 (patch) | |
tree | ec6178acfd80af10a61770f5558fa310b7afda17 /lib/kernel/src | |
parent | 33521da61673b890bcd05eda02f38fea1fe58a30 (diff) | |
download | otp-b6df9b6babb5002c5eb940e27474855abf4c5930.tar.gz otp-b6df9b6babb5002c5eb940e27474855abf4c5930.tar.bz2 otp-b6df9b6babb5002c5eb940e27474855abf4c5930.zip |
kernel: Add os:cmd/2 with max_size option
git cherry-pick 55e929c4ed5cd854038c18697123ea94948ebf35
Diffstat (limited to 'lib/kernel/src')
-rw-r--r-- | lib/kernel/src/os.erl | 37 |
1 files changed, 26 insertions, 11 deletions
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl index a90a6dcca7..dbb28c1210 100644 --- a/lib/kernel/src/os.erl +++ b/lib/kernel/src/os.erl @@ -21,7 +21,7 @@ %% Provides a common operating system interface. --export([type/0, version/0, cmd/1, find_executable/1, find_executable/2]). +-export([type/0, version/0, cmd/1, cmd/2, find_executable/1, find_executable/2]). -include("file.hrl"). @@ -32,6 +32,11 @@ putenv/2, system_time/0, system_time/1, timestamp/0, unsetenv/1]). +-type os_command() :: atom() | io_lib:chars(). +-type os_command_opts() :: #{ max_size => non_neg_integer() | infinity }. + +-export_type([os_command/0, os_command_opts/0]). + -spec getenv() -> [string()]. getenv() -> erlang:nif_error(undef). @@ -223,15 +228,21 @@ extensions() -> %% Executes the given command in the default shell for the operating system. -spec cmd(Command) -> string() when - Command :: atom() | io_lib:chars(). + Command :: os_command(). cmd(Cmd) -> + cmd(Cmd, #{ }). + +-spec cmd(Command, Options) -> string() when + Command :: os_command(), + Options :: os_command_opts(). +cmd(Cmd, Opts) -> validate(Cmd), {SpawnCmd, SpawnOpts, SpawnInput, Eot} = mk_cmd(os:type(), Cmd), Port = open_port({spawn, SpawnCmd}, [binary, stderr_to_stdout, stream, in, hide | SpawnOpts]), MonRef = erlang:monitor(port, Port), true = port_command(Port, SpawnInput), - Bytes = get_data(Port, MonRef, Eot, []), + Bytes = get_data(Port, MonRef, Eot, [], 0, maps:get(max_size, Opts, infinity)), demonitor(MonRef, [flush]), String = unicode:characters_to_list(Bytes), if %% Convert to unicode list if possible otherwise return bytes @@ -282,12 +293,13 @@ validate1([List|Rest]) when is_list(List) -> validate1([]) -> ok. -get_data(Port, MonRef, Eot, Sofar) -> +get_data(Port, MonRef, Eot, Sofar, Size, Max) -> receive {Port, {data, Bytes}} -> - case eot(Bytes, Eot) of + case eot(Bytes, Eot, Size, Max) of more -> - get_data(Port, MonRef, Eot, [Sofar,Bytes]); + get_data(Port, MonRef, Eot, [Sofar, Bytes], + Size + byte_size(Bytes), Max); Last -> catch port_close(Port), flush_until_down(Port, MonRef), @@ -298,13 +310,16 @@ get_data(Port, MonRef, Eot, Sofar) -> iolist_to_binary(Sofar) end. -eot(_Bs, <<>>) -> +eot(_Bs, <<>>, _Size, _Max) -> more; -eot(Bs, Eot) -> +eot(Bs, Eot, Size, Max) -> case binary:match(Bs, Eot) of - nomatch -> more; - {Pos, _} -> - binary:part(Bs,{0, Pos}) + nomatch when Size + byte_size(Bs) < Max -> + more; + {Pos, _} when Size + Pos < Max -> + binary:part(Bs,{0, Pos}); + _ -> + binary:part(Bs,{0, Max - Size}) end. %% When port_close returns we know that all the |