Skip to content

Commit 4272550

Browse files
cyrilloskostja
authored andcommitted
box/lua/console: Add support for lua output format
@TarantoolBot document Title: document \set output lua Historically we use YAML format to print results of operation to a console. Moreover our test engine is aiming YAML as a primary format to compare results of test runs. Still we need an ability to print results in a different fasion, in particular one may need to use the console in a REPL way so that the results would be copied and pased back to further processing. For this sake we introduce that named "output" command which allows to specify which exactly output format to use. Currently only yaml and lua formats are supported. To specify lua output format type | tarantool> \set output lua in the console. lua mode supports line oriented output (default) or block mode. For example | tarantool> a={1,2,3} | tarantool> a | --- | - - 1 | - 2 | - 3 | ... | tarantool> \set output lua | true | tarantool> a | {1, 2, 3} | tarantool> \set output lua,block | true | tarantool> a | { | 1, | 2, | 3 | } By default YAML output format is kept for now, simply to not break the test engine. The output is bound to a session, thus every new session should setup own conversion if needed. Since serializing lua data is not a trivial task we use "serpent" third party module to convert data. Part-of #3834
1 parent 6d56829 commit 4272550

File tree

5 files changed

+130
-1
lines changed

5 files changed

+130
-1
lines changed

src/box/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ lua_source(lua_sources lua/feedback_daemon.lua)
1111
lua_source(lua_sources lua/net_box.lua)
1212
lua_source(lua_sources lua/upgrade.lua)
1313
lua_source(lua_sources lua/console.lua)
14+
lua_source(lua_sources ../../third_party/serpent/src/serpent.lua)
1415
lua_source(lua_sources lua/xlog.lua)
1516
lua_source(lua_sources lua/key_def.lua)
1617
lua_source(lua_sources lua/merger.lua)

src/box/lua/console.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
#include <stdlib.h>
4747
#include <ctype.h>
4848

49+
extern char serpent_lua[];
50+
4951
static struct luaL_serializer *luaL_yaml_default = NULL;
5052

5153
/*
@@ -431,6 +433,24 @@ console_session_push(struct session *session, uint64_t sync, struct port *port)
431433
TIMEOUT_INFINITY);
432434
}
433435

436+
static void
437+
lua_serpent_init(struct lua_State *L)
438+
{
439+
static const char modname[] = "serpent";
440+
const char *modfile;
441+
442+
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
443+
modfile = lua_pushfstring(L, "@builtin/%s.lua", modname);
444+
if (luaL_loadbuffer(L, serpent_lua, strlen(serpent_lua), modfile)) {
445+
panic("Error loading Lua module %s...: %s",
446+
modname, lua_tostring(L, -1));
447+
}
448+
449+
lua_call(L, 0, 1);
450+
lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */
451+
lua_pop(L, 2);
452+
}
453+
434454
void
435455
tarantool_lua_console_init(struct lua_State *L)
436456
{
@@ -471,6 +491,12 @@ tarantool_lua_console_init(struct lua_State *L)
471491
};
472492
session_vtab_registry[SESSION_TYPE_CONSOLE] = console_session_vtab;
473493
session_vtab_registry[SESSION_TYPE_REPL] = console_session_vtab;
494+
495+
/*
496+
* Register serpent serializer as we
497+
* need it inside console REPL mode.
498+
*/
499+
lua_serpent_init(L);
474500
}
475501

476502
/*

src/box/lua/console.lua

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
-- console.lua -- internal file
22

3+
local serpent = require('serpent')
34
local internal = require('console')
45
local session_internal = require('box.internal.session')
56
local fiber = require('fiber')
@@ -13,7 +14,9 @@ local net_box = require('net.box')
1314
local YAML_TERM = '\n...\n'
1415
local PUSH_TAG_HANDLE = '!push!'
1516

16-
local function format(status, ...)
17+
local output_handlers = { }
18+
19+
output_handlers["yaml"] = function(status, opts, ...)
1720
local err
1821
if status then
1922
-- serializer can raise an exception
@@ -33,6 +36,92 @@ local function format(status, ...)
3336
return internal.format({ error = err })
3437
end
3538

39+
output_handlers["lua"] = function(status, opts, ...)
40+
local data = ...
41+
--
42+
-- Don't print nil if there is no data
43+
if data == nil then
44+
return ""
45+
end
46+
--
47+
-- Map internal symbols which serpent doesn't know
48+
-- about to a known representation.
49+
local map_symbols = function(tag, head, body, tail, level)
50+
local symbols = {
51+
['"cdata<void %*>: NULL"'] = 'box.NULL'
52+
}
53+
for k,v in pairs(symbols) do
54+
body = body:gsub(k, v)
55+
end
56+
return tag..head..body..tail
57+
end
58+
local serpent_opts = {
59+
custom = map_symbols,
60+
comment = false,
61+
}
62+
if opts == "block" then
63+
return serpent.block(..., serpent_opts)
64+
end
65+
return serpent.line(..., serpent_opts)
66+
end
67+
68+
local function output_verify_opts(fmt, opts)
69+
if opts == nil then
70+
return true, nil
71+
end
72+
if fmt == "lua" then
73+
if opts ~= "line" and opts ~= "block" then
74+
local msg = 'Wrong option "%s", expecting: line or block.'
75+
return false, msg:format(opts)
76+
end
77+
end
78+
return true, nil
79+
end
80+
81+
local function output_parse(value)
82+
local fmt, opts
83+
if value:match("([^,]+),([^,]+)") ~= nil then
84+
fmt, opts = value:match("([^,]+),([^,]+)")
85+
else
86+
fmt = value
87+
end
88+
for k, _ in pairs(output_handlers) do
89+
if k == fmt then
90+
local status, err = output_verify_opts(fmt, opts)
91+
if status ~= true then
92+
return false, err
93+
end
94+
return true, nil, fmt, opts
95+
end
96+
end
97+
local msg = 'Invalid format "%s", supported languages: lua and yaml.'
98+
return false, msg:format(value)
99+
end
100+
101+
local function output_save(fmt, opts)
102+
--
103+
-- Output format descriptors are saved per
104+
-- session thus each console may specify
105+
-- own mode.
106+
box.session.storage.console_output = {
107+
["fmt"] = fmt, ["opts"] = opts
108+
}
109+
end
110+
111+
local function format(status, ...)
112+
local d = box.session.storage.console_output
113+
--
114+
-- If there was no assignment yet provide
115+
-- a default value; for now it is YAML
116+
-- for backward compatibility sake (don't
117+
-- forget about test results which are in
118+
-- YAML format).
119+
if d == nil then
120+
d = { ["fmt"] = "yaml", ["opts"] = nil }
121+
end
122+
return output_handlers[d["fmt"]](status, d["opts"], ...)
123+
end
124+
36125
--
37126
-- Set delimiter
38127
--
@@ -71,11 +160,22 @@ local function set_language(storage, value)
71160
return true
72161
end
73162

163+
local function set_output(storage, value)
164+
local status, err, fmt, opts = output_parse(value)
165+
if status ~= true then
166+
return error(err)
167+
end
168+
output_save(fmt, opts)
169+
return true
170+
end
171+
74172
local function set_param(storage, func, param, value)
75173
local params = {
76174
language = set_language,
77175
lang = set_language,
78176
l = set_language,
177+
output = set_output,
178+
o = set_output,
79179
delimiter = set_delimiter,
80180
delim = set_delimiter,
81181
d = set_delimiter

src/lua/help_en_US.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ To start the interactive Tarantool tutorial, type 'tutorial()' here.
88
Available backslash commands:
99
1010
\set language <language> -- set language (lua or sql)
11+
\set output <format> -- set output format (lua[,line|block] or yaml)
1112
\set delimiter <delimiter> -- set expression delimiter
1213
\help -- show this screen
1314
\quit -- quit interactive console

test/box/admin.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ help()
2020
Available backslash commands:
2121

2222
\set language <language> -- set language (lua or sql)
23+
\set output <format> -- set output format (lua[,line|block] or yaml)
2324
\set delimiter <delimiter> -- set expression delimiter
2425
\help -- show this screen
2526
\quit -- quit interactive console

0 commit comments

Comments
 (0)