File 2241-shell-history-allow-configurable-history-module.patch of Package erlang
From b78f444e56815adc4865134ccaa70a5a4b7e68da Mon Sep 17 00:00:00 2001
From: Maxim Fedorov <dane@whatsapp.com>
Date: Mon, 21 Dec 2020 16:22:35 -0800
Subject: [PATCH] shell history: allow configurable history module
In addition to 'enabled' or 'disabled' setting, kernel
shell_history variable may be an atom that allows to use
any module as callback module for shell history.
This enabled to fetch shell history from different sources,
for example, cloud-based environment, or other nodes of
a cluster.
This commit also fixes test case that was using -kernel
shell_history 'true' instead of 'enabled'.
---
lib/kernel/doc/src/kernel_app.xml | 10 +++++--
lib/kernel/src/group_history.erl | 16 +++++++-----
lib/kernel/test/interactive_shell_SUITE.erl | 29 ++++++++++++++++++---
3 files changed, 44 insertions(+), 11 deletions(-)
diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index d4f707951d..74cf089918 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -446,10 +446,16 @@ MaxT = TickTime + TickTime / 4</code>
using this service.</p>
<p>Defaults to <c>false</c>.</p>
</item>
- <tag><c>shell_history = enabled | disabled </c></tag>
+ <tag><c>shell_history = enabled | disabled | module()</c></tag>
<item>
<p>Specifies whether shell history should be logged to disk
- between usages of <c>erl</c>.</p>
+ between usages of <c>erl</c> (<c>enabled</c>), not logged
+ at all (<c>disabled</c>), or a user-specified module will
+ be used to log shell history. This module should export
+ <c>load() -> [string()]</c> returning a list of strings to
+ load in the shell when it starts, and <c>add(iodata()) -> ok.</c>
+ called every time new line is entered in the shell. By default
+ logging is disabled.</p>
</item>
<tag><c>shell_history_drop = [string()]</c></tag>
<item>
diff --git a/lib/kernel/src/group_history.erl b/lib/kernel/src/group_history.erl
index bbe5a8077e..c196b0c1a9 100644
--- a/lib/kernel/src/group_history.erl
+++ b/lib/kernel/src/group_history.erl
@@ -73,8 +73,10 @@ load() ->
% the node is shutting down. Ignore it.
exit:_ -> []
end;
- _ ->
- []
+ disabled ->
+ [];
+ Provider ->
+ Provider:load()
end.
%% @doc adds a log line to the erlang history log, if configured to do so.
@@ -98,7 +100,9 @@ add(Line, enabled) ->
ok
end;
add(_Line, disabled) ->
- ok.
+ ok;
+add(Line, Provider) ->
+ lists:member(Line, to_drop()) orelse Provider:add(Line).
%%%%%%%%%%%%%%%
%%% PRIVATE %%%
@@ -129,13 +133,13 @@ repair_log(Name) ->
load().
%% Return whether the shell history is enabled or not
--spec history_status() -> enabled | disabled.
+-spec history_status() -> enabled | disabled | module().
history_status() ->
%% Don't run for user proc or if the emulator's tearing down
Skip = is_user() orelse not init_running(),
case application:get_env(kernel, shell_history) of
- {ok, enabled} when not Skip ->
- enabled;
+ {ok, Atom} when not Skip, is_atom(Atom) ->
+ Atom;
undefined when not Skip ->
?DEFAULT_STATUS;
_ ->
diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl
index f058b53497..b4ca502dc4 100644
--- a/lib/kernel/test/interactive_shell_SUITE.erl
+++ b/lib/kernel/test/interactive_shell_SUITE.erl
@@ -22,7 +22,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
get_columns_and_rows/1, exit_initial/1, job_control_local/1,
- job_control_remote/1,stop_during_init/1,
+ job_control_remote/1,stop_during_init/1, custom_shell_history/1,
job_control_remote_noshell/1,ctrl_keys/1,
get_columns_and_rows_escript/1,
remsh/1, remsh_longnames/1, remsh_no_epmd/1]).
@@ -30,6 +30,8 @@
-export([init_per_testcase/2, end_per_testcase/2]).
%% For spawn
-export([toerl_server/3]).
+%% Exports for custom shell history module
+-export([load/0, add/1]).
init_per_testcase(_Func, Config) ->
Config.
@@ -45,7 +47,7 @@ all() ->
[get_columns_and_rows_escript,get_columns_and_rows,
exit_initial, job_control_local,
job_control_remote, job_control_remote_noshell,
- ctrl_keys, stop_during_init,
+ ctrl_keys, stop_during_init, custom_shell_history,
remsh, remsh_longnames, remsh_no_epmd].
groups() ->
@@ -216,13 +218,34 @@ stop_during_init(Config) when is_list(Config) ->
{error, Reason2} ->
{skip, Reason2};
Tempdir ->
- XArg = " -kernel shell_history true -s init stop",
+ XArg = " -kernel shell_history enabled -s init stop",
start_runerl_command(RunErl, Tempdir, "\\\""++Erl++"\\\""++XArg),
{ok, Binary} = file:read_file(filename:join(Tempdir, "erlang.log.1")),
nomatch = binary:match(Binary, <<"*** ERROR: Shell process terminated! ***">>)
end
end.
+custom_shell_history(Config) when is_list(Config) ->
+ case proplists:get_value(default_shell, Config) of
+ old -> {skip, "Not supported in old shell"};
+ new ->%% Up key: Ctrl + P = Cp=[$\^p]
+ rtnode([
+ {putline, ""},
+ {putline, [$\^p]},
+ {putline_raw, ""},
+ {getline, "0"},
+ {putline, "echo."},
+ {getline, "!echo"} %% exclamation sign is printed by custom history module
+ ], [], [], " -kernel shell_history " ++ atom_to_list(?MODULE) ++
+ " -pz " ++ filename:dirname(code:which(?MODULE)))
+ end.
+
+load() ->
+ ["0.\n\n"].
+
+add(_Line) ->
+ io:format("!", []).
+
%% Tests that local shell can be started by means of job control.
job_control_local(Config) when is_list(Config) ->
case proplists:get_value(default_shell,Config) of
--
2.26.2