Skip to content

Commit

Permalink
lua: add -e and -l command line options
Browse files Browse the repository at this point in the history
  -e EXPR - execute string 'EXPR
  -l NAME - require library 'NAME'

A part of tarantool#1265
  • Loading branch information
rtsisyk committed Aug 22, 2017
1 parent 516e870 commit 9e45b41
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 12 deletions.
49 changes: 47 additions & 2 deletions src/lua/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,8 +492,51 @@ run_script_f(va_list ap)
struct lua_State *L = va_arg(ap, struct lua_State *);
const char *path = va_arg(ap, const char *);
bool interactive = va_arg(ap, int);
int optc = va_arg(ap, int);
char **optv = va_arg(ap, char **);
int argc = va_arg(ap, int);
char **argv = va_arg(ap, char **);
struct diag *diag = &fiber()->diag;

/*
* Load libraries and execute chunks passed by -l and -e
* command line options
*/
for (int i = 0; i < optc; i += 2) {
assert(optv[i][0] == '-' && optv[i][2] == '\0');
switch (optv[i][1]) {
case 'l':
/*
* Load library
*/
lua_getglobal(L, "require");
lua_pushstring(L, optv[i + 1]);
if (luaT_call(L, 1, 1) != 0) {
struct error *e = diag_last_error(diag);
panic("%s", e->errmsg);
}
/* Non-standard: set name = require('name') */
lua_setglobal(L, optv[i + 1]);
lua_settop(L, 0);
break;
case 'e':
/*
* Execute chunk
*/
if (luaL_loadbuffer(L, optv[i + 1], strlen(optv[i + 1]),
"=(command line)") != 0) {
panic("%s", lua_tostring(L, -1));
}
if (luaT_call(L, 0, 0) != 0) {
struct error *e = diag_last_error(diag);
panic("%s", e->errmsg);
}
lua_settop(L, 0);
break;
default:
unreachable(); /* checked by getopt() in main() */
}
}

/*
* Return control to tarantool_lua_run_script.
Expand Down Expand Up @@ -542,7 +585,8 @@ run_script_f(va_list ap)
}

void
tarantool_lua_run_script(char *path, bool interactive, int argc, char **argv)
tarantool_lua_run_script(char *path, bool interactive,
int optc, char **optv, int argc, char **argv)
{
const char *title = path ? basename(path) : "interactive";
/*
Expand All @@ -555,7 +599,8 @@ tarantool_lua_run_script(char *path, bool interactive, int argc, char **argv)
script_fiber = fiber_new(title, run_script_f);
if (script_fiber == NULL)
panic("%s", diag_last_error(diag_get())->errmsg);
fiber_start(script_fiber, tarantool_L, path, interactive, argc, argv);
fiber_start(script_fiber, tarantool_L, path, interactive,
optc, optv, argc, argv);

/*
* Run an auxiliary event loop to re-schedule run_script fiber.
Expand Down
5 changes: 3 additions & 2 deletions src/lua/init.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ tarantool_lua_tostring(struct lua_State *L, int index);
* @param argv argv command line arguments
*/
void
tarantool_lua_run_script(char *path, bool force_interactive, int argc,
char **argv);
tarantool_lua_run_script(char *path, bool force_interactive,
int optc, char **optv,
int argc, char **argv);

extern char *history;

Expand Down
27 changes: 24 additions & 3 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,8 @@ print_help(const char *program)
puts("When no script name is provided, the server responds to:");
puts(" -h, --help\t\t\tdisplay this help and exit");
puts(" -V, --version\t\t\tprint program version and exit");
puts(" -e EXPR\t\t\texecute string 'EXPR'");
puts(" -l NAME\t\t\trequire library 'NAME'");
puts(" -i\t\t\t\tenter interactive mode after executing 'SCRIPT'");
puts("");
puts("Please visit project home page at http://tarantool.org");
Expand All @@ -551,13 +553,17 @@ main(int argc, char **argv)

/* Enter interactive mode after executing 'script' */
bool interactive = false;
/* Lua interpeter options, e.g. -e and -l */
int optc = 0;
char **optv = NULL;
auto guard = make_scoped_guard([=]{ if (optc) free(optv); });

static struct option longopts[] = {
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{NULL, 0, 0, 0},
};
static const char *opts = "+hVi";
static const char *opts = "+hVie:l:";

int ch;
while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) {
Expand All @@ -572,6 +578,21 @@ main(int argc, char **argv)
/* Force interactive mode */
interactive = true;
break;
case 'l':
case 'e':
/* Save Lua interepter options to optv as is */
if (optc == 0) {
optv = (char **) calloc(argc, sizeof(char *));
if (optv == NULL)
panic_syserror("No enough memory for arguments");
}
/*
* The variable optind is the index of the next
* element to be processed in argv.
*/
optv[optc++] = argv[optind - 2];
optv[optc++] = argv[optind - 1];
break;
default:
/* "invalid option" is printed by getopt */
return EX_USAGE;
Expand Down Expand Up @@ -655,8 +676,8 @@ main(int argc, char **argv)
* is why script must run only after the server was fully
* initialized.
*/
tarantool_lua_run_script(script, interactive, main_argc,
main_argv);
tarantool_lua_run_script(script, interactive, optc, optv,
main_argc, main_argv);
/*
* Start event loop after executing Lua script if signal_cb()
* wasn't triggered and there is some new events. Initial value
Expand Down
5 changes: 5 additions & 0 deletions test/box-py/args.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env tarantool

for i=-1,#arg do
print(string.format("arg[%d] => %s", i, arg[i]))
end
89 changes: 86 additions & 3 deletions test/box-py/args.result
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ All command line options are passed to the interpreted script.
When no script name is provided, the server responds to:
-h, --help display this help and exit
-V, --version print program version and exit
-e EXPR execute string 'EXPR'
-l NAME require library 'NAME'
-i enter interactive mode after executing 'SCRIPT'

Please visit project home page at http://tarantool.org
Expand All @@ -21,19 +23,21 @@ All command line options are passed to the interpreted script.
When no script name is provided, the server responds to:
-h, --help display this help and exit
-V, --version print program version and exit
-e EXPR execute string 'EXPR'
-l NAME require library 'NAME'
-i enter interactive mode after executing 'SCRIPT'

Please visit project home page at http://tarantool.org
to see online documentation, submit bugs or contribute a patch.

tarantool -Z
tarantool: invalid option -- 'Z'
${SOURCEDIR}/src/tarantool: invalid option -- 'Z'

tarantool --no-such-option
tarantool: unrecognized option '--no-such-option'
${SOURCEDIR}/src/tarantool: unrecognized option '--no-such-option'

tarantool --no-such-option --version
tarantool: unrecognized option '--no-such-option'
${SOURCEDIR}/src/tarantool: unrecognized option '--no-such-option'

tarantool --version
Tarantool 1.minor.patch-<rev>-<commit>
Expand All @@ -51,3 +55,82 @@ Compiler: cc
C_FLAGS: flags
CXX_FLAGS: flags

tarantool ${SOURCEDIR}/test/box-py/args.lua
arg[-1] => ${SOURCEDIR}/src/tarantool
arg[0] => ${SOURCEDIR}/test/box-py/args.lua

tarantool ${SOURCEDIR}/test/box-py/args.lua 1 2 3
arg[-1] => ${SOURCEDIR}/src/tarantool
arg[0] => ${SOURCEDIR}/test/box-py/args.lua
arg[1] => 1
arg[2] => 2
arg[3] => 3

tarantool ${SOURCEDIR}/test/box-py/args.lua 1 2 3 -V
arg[-1] => ${SOURCEDIR}/src/tarantool
arg[0] => ${SOURCEDIR}/test/box-py/args.lua
arg[1] => 1
arg[2] => 2
arg[3] => 3
arg[4] => -V

tarantool ${SOURCEDIR}/test/box-py/args.lua -V 1 2 3
arg[-1] => ${SOURCEDIR}/src/tarantool
arg[0] => ${SOURCEDIR}/test/box-py/args.lua
arg[1] => -V
arg[2] => 1
arg[3] => 2
arg[4] => 3

tarantool ${SOURCEDIR}/test/box-py/args.lua 1 2 3 --help
arg[-1] => ${SOURCEDIR}/src/tarantool
arg[0] => ${SOURCEDIR}/test/box-py/args.lua
arg[1] => 1
arg[2] => 2
arg[3] => 3
arg[4] => --help

tarantool ${SOURCEDIR}/test/box-py/args.lua --help 1 2 3
arg[-1] => ${SOURCEDIR}/src/tarantool
arg[0] => ${SOURCEDIR}/test/box-py/args.lua
arg[1] => --help
arg[2] => 1
arg[3] => 2
arg[4] => 3

tarantool -V ${SOURCEDIR}/test/box-py/args.lua 1 2 3
Tarantool 1.minor.patch-<rev>-<commit>
Target: platform <build>
Build options: flags
Compiler: cc
C_FLAGS: flags
CXX_FLAGS: flags

tarantool -e print('Hello') ${SOURCEDIR}/test/box-py/args.lua 1 2 3
Hello
arg[-1] => ${SOURCEDIR}/src/tarantool
arg[0] => ${SOURCEDIR}/test/box-py/args.lua
arg[1] => 1
arg[2] => 2
arg[3] => 3

tarantool -e a = 10 -e print(a) ${SOURCEDIR}/test/box-py/args.lua 1 2 3 --help
10
arg[-1] => ${SOURCEDIR}/src/tarantool
arg[0] => ${SOURCEDIR}/test/box-py/args.lua
arg[1] => 1
arg[2] => 2
arg[3] => 3
arg[4] => --help

tarantool -e print(rawget(_G, 'log') == nil) -e io.flush() -l log -e print(log.info('Hello')) ${SOURCEDIR}/test/box-py/args.lua 1 2 3 --help
true
Hello

arg[-1] => ${SOURCEDIR}/src/tarantool
arg[0] => ${SOURCEDIR}/test/box-py/args.lua
arg[1] => 1
arg[2] => 2
arg[3] => 3
arg[4] => --help

28 changes: 26 additions & 2 deletions test/box-py/args.test.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import sys
import os
import re

# mask BFD warnings: https://bugs.launchpad.net/tarantool/+bug/1018356
sys.stdout.push_filter("unable to read unknown load command 0x2\d+", "")
server.test_option("--help")
server.test_option("-h")
sys.stdout.push_filter("(/\S+)+/tarantool", "tarantool")
# Replace with the same value for case when builddir inside source dir
sys.stdout.push_filter(re.escape(os.getenv("BUILDDIR")), "${SOURCEDIR}")
sys.stdout.push_filter(re.escape(os.getenv("SOURCEDIR")), "${SOURCEDIR}")
server.test_option("-Z")
server.test_option("--no-such-option")
server.test_option("--no-such-option --version")
Expand All @@ -19,7 +22,28 @@

server.test_option("--version")
server.test_option("-V ")
sys.stdout.clear_all_filters()

script = os.getenv("SOURCEDIR") + "/test/box-py/args.lua"
server.test_option(script)
server.test_option(script + " 1 2 3")
server.test_option(script + " 1 2 3 -V")
server.test_option(script + " -V 1 2 3")
server.test_option(script + " 1 2 3 --help")
server.test_option(script + " --help 1 2 3")
server.test_option("-V " + script + " 1 2 3")

server.test_option("-e \"print('Hello')\" " + script + " 1 2 3")
server.test_option("-e \"a = 10\" " + \
"-e print(a) " + \
script + \
" 1 2 3 --help")
server.test_option("-e \"print(rawget(_G, 'log') == nil)\" " + \
"-e io.flush() " + \
"-l log " + \
"-e \"print(log.info('Hello'))\" " + \
script + \
" 1 2 3 --help")

sys.stdout.clear_all_filters()
# Args filter cleanup
# vim: syntax=python

0 comments on commit 9e45b41

Please sign in to comment.