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

openSUSE Build Service is sponsored by