Merge pull request #576 from psychon/spawn_exit_code
At exit code support to spawn
This commit is contained in:
commit
69da6ee0db
|
@ -91,17 +91,27 @@ end
|
||||||
|
|
||||||
--- Spawn a program and asynchronously and capture its output line by line.
|
--- Spawn a program and asynchronously and capture its output line by line.
|
||||||
-- @tparam string|table cmd The command.
|
-- @tparam string|table cmd The command.
|
||||||
-- @tparam[opt] function stdout_callback Function that is called with each line of
|
-- @tab callbacks Table containing callbacks that should be
|
||||||
-- output on stdout, e.g. `stdout_callback(line)`.
|
-- invoked on various conditions.
|
||||||
-- @tparam[opt] function stderr_callback Function that is called with each line of
|
-- @tparam[opt] function callbacks.stdout Function that is called with each line of
|
||||||
-- output on stderr, e.g. `stderr_callback(line)`.
|
-- output on stdout, e.g. `stdout(line)`.
|
||||||
-- @tparam[opt] function done_callback Function to call when no more output is
|
-- @tparam[opt] function callbacks.stderr Function that is called with each line of
|
||||||
-- produced.
|
-- output on stderr, e.g. `stderr(line)`.
|
||||||
|
-- @tparam[opt] function callbacks.output_done Function to call when no more output
|
||||||
|
-- is produced.
|
||||||
|
-- @tparam[opt] function callbacks.exit Function to call when the spawned process
|
||||||
|
-- exits. This function gets the exit reason and code as its argument. The
|
||||||
|
-- reason can be "exit" or "signal". For "exit", the second argument is the exit
|
||||||
|
-- code. For "signal", the second argument is the signal causing process
|
||||||
|
-- termination.
|
||||||
-- @treturn[1] Integer the PID of the forked process.
|
-- @treturn[1] Integer the PID of the forked process.
|
||||||
-- @treturn[2] string Error message.
|
-- @treturn[2] string Error message.
|
||||||
function spawn.with_line_callback(cmd, stdout_callback, stderr_callback, done_callback)
|
function spawn.with_line_callback(cmd, callbacks)
|
||||||
|
local stdout_callback, stderr_callback, done_callback, exit_callback =
|
||||||
|
callbacks.stdout, callbacks.stderr, callbacks.output_done, callbacks.exit
|
||||||
local have_stdout, have_stderr = stdout_callback ~= nil, stderr_callback ~= nil
|
local have_stdout, have_stderr = stdout_callback ~= nil, stderr_callback ~= nil
|
||||||
local pid, sn_id, stdin, stdout, stderr = capi.awesome.spawn(cmd, false, false, have_stdout, have_stderr)
|
local pid, sn_id, stdin, stdout, stderr = capi.awesome.spawn(cmd,
|
||||||
|
false, false, have_stdout, have_stderr, exit_callback)
|
||||||
if type(pid) == "string" then
|
if type(pid) == "string" then
|
||||||
-- Error
|
-- Error
|
||||||
return pid
|
return pid
|
||||||
|
|
42
spawn.c
42
spawn.c
|
@ -342,6 +342,28 @@ parse_command(lua_State *L, int idx, GError **error)
|
||||||
return argv;
|
return argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Callback for when a spawned process exits. */
|
||||||
|
static void
|
||||||
|
child_exit_callback(GPid pid, gint status, gpointer user_data)
|
||||||
|
{
|
||||||
|
lua_State *L = globalconf_get_lua_State();
|
||||||
|
int exit_callback = GPOINTER_TO_INT(user_data);
|
||||||
|
|
||||||
|
/* 'Decode' the exit status */
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
lua_pushliteral(L, "exit");
|
||||||
|
lua_pushnumber(L, WEXITSTATUS(status));
|
||||||
|
} else {
|
||||||
|
assert(WIFSIGNALED(status));
|
||||||
|
lua_pushliteral(L, "signal");
|
||||||
|
lua_pushnumber(L, WTERMSIG(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, exit_callback);
|
||||||
|
luaA_dofunction(L, 2, 0);
|
||||||
|
luaA_unregister(L, &exit_callback);
|
||||||
|
}
|
||||||
|
|
||||||
/** Spawn a program.
|
/** Spawn a program.
|
||||||
* The program will be started on the default screen.
|
* The program will be started on the default screen.
|
||||||
*
|
*
|
||||||
|
@ -350,6 +372,9 @@ parse_command(lua_State *L, int idx, GError **error)
|
||||||
* @tparam[opt=false] boolean stdin Return a fd for stdin?
|
* @tparam[opt=false] boolean stdin Return a fd for stdin?
|
||||||
* @tparam[opt=false] boolean stdout Return a fd for stdout?
|
* @tparam[opt=false] boolean stdout Return a fd for stdout?
|
||||||
* @tparam[opt=false] boolean stderr Return a fd for stderr?
|
* @tparam[opt=false] boolean stderr Return a fd for stderr?
|
||||||
|
* @tparam[opt=nil] function exit_callback Function to call on process exit. The
|
||||||
|
* function arguments will be type of exit ("exit" or "signal") and the exit
|
||||||
|
* code / the signal number causing process termination.
|
||||||
* @treturn[1] integer Process ID if everything is OK.
|
* @treturn[1] integer Process ID if everything is OK.
|
||||||
* @treturn[1] string Startup-notification ID, if `use_sn` is true.
|
* @treturn[1] string Startup-notification ID, if `use_sn` is true.
|
||||||
* @treturn[1] integer stdin, if `stdin` is true.
|
* @treturn[1] integer stdin, if `stdin` is true.
|
||||||
|
@ -365,6 +390,7 @@ luaA_spawn(lua_State *L)
|
||||||
bool use_sn = true, return_stdin = false, return_stdout = false, return_stderr = false;
|
bool use_sn = true, return_stdin = false, return_stdout = false, return_stderr = false;
|
||||||
int stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
|
int stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
|
||||||
int *stdin_ptr = NULL, *stdout_ptr = NULL, *stderr_ptr = NULL;
|
int *stdin_ptr = NULL, *stdout_ptr = NULL, *stderr_ptr = NULL;
|
||||||
|
GSpawnFlags flags = 0;
|
||||||
gboolean retval;
|
gboolean retval;
|
||||||
GPid pid;
|
GPid pid;
|
||||||
|
|
||||||
|
@ -376,6 +402,11 @@ luaA_spawn(lua_State *L)
|
||||||
return_stdout = luaA_checkboolean(L, 4);
|
return_stdout = luaA_checkboolean(L, 4);
|
||||||
if(lua_gettop(L) >= 5)
|
if(lua_gettop(L) >= 5)
|
||||||
return_stderr = luaA_checkboolean(L, 5);
|
return_stderr = luaA_checkboolean(L, 5);
|
||||||
|
if(lua_gettop(L) >= 6)
|
||||||
|
{
|
||||||
|
luaA_checkfunction(L, 6);
|
||||||
|
flags |= G_SPAWN_DO_NOT_REAP_CHILD;
|
||||||
|
}
|
||||||
if(return_stdin)
|
if(return_stdin)
|
||||||
stdin_ptr = &stdin_fd;
|
stdin_ptr = &stdin_fd;
|
||||||
if(return_stdout)
|
if(return_stdout)
|
||||||
|
@ -409,7 +440,8 @@ luaA_spawn(lua_State *L)
|
||||||
g_timeout_add_seconds(AWESOME_SPAWN_TIMEOUT, spawn_launchee_timeout, context);
|
g_timeout_add_seconds(AWESOME_SPAWN_TIMEOUT, spawn_launchee_timeout, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
|
flags |= G_SPAWN_SEARCH_PATH;
|
||||||
|
retval = g_spawn_async_with_pipes(NULL, argv, NULL, flags,
|
||||||
spawn_callback, context, &pid,
|
spawn_callback, context, &pid,
|
||||||
stdin_ptr, stdout_ptr, stderr_ptr, &error);
|
stdin_ptr, stdout_ptr, stderr_ptr, &error);
|
||||||
g_strfreev(argv);
|
g_strfreev(argv);
|
||||||
|
@ -424,6 +456,14 @@ luaA_spawn(lua_State *L)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(flags & G_SPAWN_DO_NOT_REAP_CHILD)
|
||||||
|
{
|
||||||
|
int exit_callback = LUA_REFNIL;
|
||||||
|
/* Only do this down here to avoid leaks in case of errors */
|
||||||
|
luaA_registerfct(L, 6, &exit_callback);
|
||||||
|
g_child_watch_add(pid, child_exit_callback, GINT_TO_POINTER(exit_callback));
|
||||||
|
}
|
||||||
|
|
||||||
/* push pid on stack */
|
/* push pid on stack */
|
||||||
lua_pushnumber(L, pid);
|
lua_pushnumber(L, pid);
|
||||||
|
|
||||||
|
|
|
@ -3,40 +3,61 @@
|
||||||
local spawn = require("awful.spawn")
|
local spawn = require("awful.spawn")
|
||||||
|
|
||||||
local spawns_done = 0
|
local spawns_done = 0
|
||||||
|
local exit_yay, exit_snd = nil, nil
|
||||||
|
|
||||||
local steps = {
|
local steps = {
|
||||||
function(count)
|
function(count)
|
||||||
if count == 1 then
|
if count == 1 then
|
||||||
local steps_yay = 0
|
local steps_yay = 0
|
||||||
spawn.with_line_callback("echo yay", function(line)
|
spawn.with_line_callback("echo yay", {
|
||||||
|
stdout = function(line)
|
||||||
assert(line == "yay", "line == '" .. tostring(line) .. "'")
|
assert(line == "yay", "line == '" .. tostring(line) .. "'")
|
||||||
assert(steps_yay == 0)
|
assert(steps_yay == 0)
|
||||||
steps_yay = steps_yay + 1
|
steps_yay = steps_yay + 1
|
||||||
end, nil, function()
|
end,
|
||||||
|
output_done = function()
|
||||||
assert(steps_yay == 1)
|
assert(steps_yay == 1)
|
||||||
steps_yay = steps_yay + 1
|
steps_yay = steps_yay + 1
|
||||||
spawns_done = spawns_done + 1
|
spawns_done = spawns_done + 1
|
||||||
end)
|
end,
|
||||||
|
exit = function(reason, code)
|
||||||
|
assert(reason == "exit")
|
||||||
|
assert(exit_yay == nil)
|
||||||
|
assert(code == 0)
|
||||||
|
exit_yay = code
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
local steps_count = 0
|
local steps_count = 0
|
||||||
local err_count = 0
|
local err_count = 0
|
||||||
spawn.with_line_callback({ "sh", "-c", "printf line1\\\\nline2\\\\nline3 ; echo err >&2" },
|
spawn.with_line_callback({ "sh", "-c", "printf line1\\\\nline2\\\\nline3 ; echo err >&2 ; exit 42" }, {
|
||||||
function(line)
|
stdout = function(line)
|
||||||
assert(steps_count < 3)
|
assert(steps_count < 3)
|
||||||
steps_count = steps_count + 1
|
steps_count = steps_count + 1
|
||||||
assert(line == "line" .. steps_count, "line == '" .. tostring(line) .. "'")
|
assert(line == "line" .. steps_count, "line == '" .. tostring(line) .. "'")
|
||||||
end, function(line)
|
end,
|
||||||
|
stderr = function(line)
|
||||||
assert(err_count == 0)
|
assert(err_count == 0)
|
||||||
err_count = err_count + 1
|
err_count = err_count + 1
|
||||||
assert(line == "err", "line == '" .. tostring(line) .. "'")
|
assert(line == "err", "line == '" .. tostring(line) .. "'")
|
||||||
end, function()
|
end,
|
||||||
|
output_done = function()
|
||||||
assert(steps_count == 3)
|
assert(steps_count == 3)
|
||||||
assert(err_count == 1)
|
assert(err_count == 1)
|
||||||
steps_count = steps_count + 1
|
steps_count = steps_count + 1
|
||||||
spawns_done = spawns_done + 1
|
spawns_done = spawns_done + 1
|
||||||
end)
|
end,
|
||||||
|
exit = function(reason, code)
|
||||||
|
assert(reason == "exit")
|
||||||
|
assert(exit_snd == nil)
|
||||||
|
assert(code == 42)
|
||||||
|
exit_snd = code
|
||||||
|
end
|
||||||
|
})
|
||||||
end
|
end
|
||||||
if spawns_done == 2 then
|
if spawns_done == 2 then
|
||||||
|
assert(exit_yay == 0)
|
||||||
|
assert(exit_snd == 42)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
Loading…
Reference in New Issue