Skip to content

Commit

Permalink
detach std file
Browse files Browse the repository at this point in the history
  • Loading branch information
actboy168 committed Nov 20, 2023
1 parent c3cb76d commit feedf28
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 29 deletions.
48 changes: 34 additions & 14 deletions binding/lua_subprocess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,35 @@ namespace bee::lua_subprocess {
}
}

static void process_close_std(lua_State* L) {
if (LUA_TTABLE == lua_getiuservalue(L, 1, 1)) {
for (auto name : { "stdin", "stdout", "stderr" }) {
if (LUA_TNIL != lua_getfield(L, -1, name)) {
if (LUA_TTABLE == lua_getmetatable(L, -1)) {
if (LUA_TFUNCTION == lua_getfield(L, -1, "__close")) {
lua_pushvalue(L, -2);
lua_call(L, 1, 0);
}
lua_pop(L, 1);
}
lua_pop(L, 1);
}
lua_pop(L, 1);
}
}
lua_pop(L, 1);
}

static int detach(lua_State* L) {
auto& self = to(L, 1);
process_close_std(L);
lua_pushboolean(L, self.detach());
return 1;
}

static int mt_close(lua_State* L) {
auto& self = to(L, 1);
process_close_std(L);
process_detach(L, self);
return 0;
}
Expand Down Expand Up @@ -123,18 +144,21 @@ namespace bee::lua_subprocess {
return 0;
}

static int mt_newindex(lua_State* L) {
if (LUA_TTABLE != lua_getiuservalue(L, 1, 1)) {
static bool set_uservalue(lua_State* L, const char* name) {
if (LUA_TTABLE != lua_getiuservalue(L, -1, 1)) {
lua_pop(L, 1);
lua_newtable(L);
lua_pushvalue(L, -1);
if (!lua_setiuservalue(L, 1, 1)) {
return 0;
if (!lua_setiuservalue(L, -3, 1)) {
lua_remove(L, -3);
lua_pop(L, 1);
return false;
}
}
lua_insert(L, -3);
lua_rawset(L, -3);
return 0;
lua_rotate(L, -3, 2);
lua_setfield(L, -2, name);
lua_pop(L, 1);
return true;
}

static void metatable(lua_State* L) {
Expand All @@ -153,7 +177,6 @@ namespace bee::lua_subprocess {
lua_pushcclosure(L, mt_index, 1);
lua_setfield(L, -2, "__index");
static luaL_Reg mt[] = {
{ "__newindex", mt_newindex },
{ "__close", mt_close },
{ "__gc", mt_gc },
{ NULL, NULL }
Expand Down Expand Up @@ -404,16 +427,13 @@ namespace bee::lua_subprocess {
}
process::constructor(L, spawn);
if (f_stderr) {
lua_insert(L, -2);
lua_setfield(L, -2, "stderr");
process::set_uservalue(L, "stderr");
}
if (f_stdout) {
lua_insert(L, -2);
lua_setfield(L, -2, "stdout");
process::set_uservalue(L, "stdout");
}
if (f_stdin) {
lua_insert(L, -2);
lua_setfield(L, -2, "stdin");
process::set_uservalue(L, "stdin");
}
return 1;
}
Expand Down
45 changes: 30 additions & 15 deletions test/test_subprocess.lua
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,18 @@ end

function test_subprocess:test_stdio_1()
local process = shell:runlua('io.stdout:write("ok")', { stdout = true })
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertIsUserdata(process.stdout)
lt.assertEquals(process.stdout:read(2), "ok")
lt.assertEquals(process.stdout:read(2), nil)
lt.assertEquals(process:detach(), true)

local process = shell:runlua('io.stderr:write("ok")', { stderr = true })
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertIsUserdata(process.stderr)
lt.assertEquals(process.stderr:read(2), "ok")
lt.assertEquals(process.stderr:read(2), nil)
lt.assertEquals(process:detach(), true)

local process = shell:runlua('io.write(io.read "a")', { stdin = true, stdout = true, stderr = true })
lt.assertIsUserdata(process.stdin)
Expand All @@ -137,14 +139,16 @@ function test_subprocess:test_stdio_1()
lt.assertEquals(process:is_running(), true)
process.stdin:write "ok"
process.stdin:close()
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertEquals(process.stdout:read(2), "ok")
lt.assertEquals(process.stdout:read(2), nil)
lt.assertEquals(process:detach(), true)

local process = shell:runlua('error "Test subprocess error."', { stderr = true })
safe_exit(process, 1)
lt.assertEquals(process:wait(), 1)
local found = not not string.find(process.stderr:read "a", "Test subprocess error.", nil, true)
lt.assertEquals(found, true)
lt.assertEquals(process:detach(), true)
end

function test_subprocess:test_stdio_2()
Expand Down Expand Up @@ -178,20 +182,22 @@ function test_subprocess:test_stdio_2()
local process1 = shell:runlua('io.write "ok"', { stdout = true })
local process2 = shell:runlua('io.write(io.read "a")', { stdin = process1.stdout, stdout = true })
safe_exit(process1)
safe_exit(process2)
lt.assertEquals(process2:wait(), 0)
lt.assertEquals(process2.stdout:read "a", "ok")
lt.assertEquals(process2:detach(), true)
end

function test_subprocess:test_stdio_3()
local process = shell:runlua([[
io.stdout:write "[stdout]"; io.stdout:flush()
io.stderr:write "[stderr]"; io.stderr:flush()
]], { stdout = true, stderr = "stdout" })
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertIsUserdata(process.stdout)
lt.assertIsUserdata(process.stderr)
lt.assertEquals(process.stdout, process.stderr)
lt.assertEquals(process.stdout:read "a", "[stdout][stderr]")
lt.assertEquals(process:detach(), true)
end

function test_subprocess:test_stdio_4()
Expand All @@ -217,26 +223,29 @@ function test_subprocess:test_stdio_4()
end
process.stdin:write "EXIT"
process.stdin:close()
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertEquals(process.stdout:read(4), nil)
lt.assertEquals(process:detach(), true)
end

function test_subprocess:test_peek()
local process = shell:runlua('io.write "ok"', { stdout = true })
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertIsUserdata(process.stdout)
lt.assertEquals(subprocess.peek(process.stdout), 2)
lt.assertEquals(subprocess.peek(process.stdout), 2)
lt.assertEquals(process.stdout:read(2), "ok")
lt.assertEquals(subprocess.peek(process.stdout), nil)
lt.assertEquals(process:detach(), true)

local process = shell:runlua('io.write "ok"', { stdout = true })
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertIsUserdata(process.stdout)
lt.assertEquals(subprocess.peek(process.stdout), 2)
process.stdout:close()
lt.assertError("attempt to use a closed file", process.stdout.read, process.stdout, 2)
lt.assertEquals(subprocess.peek(process.stdout), nil)
lt.assertEquals(process:detach(), true)

local process = shell:runlua('io.stdout:setvbuf "no" io.write "start" io.write(io.read "a")', { stdin = true, stdout = true })
lt.assertIsUserdata(process.stdin)
Expand All @@ -252,9 +261,10 @@ function test_subprocess:test_peek()
end
process.stdin:write "ok"
process.stdin:close()
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertEquals(process.stdout:read(2), "ok")
lt.assertEquals(process.stdout:read(2), nil)
lt.assertEquals(process:detach(), true)
end

function test_subprocess:test_filemode()
Expand All @@ -264,8 +274,9 @@ function test_subprocess:test_filemode()
]], { stdin = true, stderr = true })
process.stdin:write "\r\n"
process.stdin:close()
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertEquals(process.stderr:read "a", "")
lt.assertEquals(process:detach(), true)
end
local process = shell:runlua([[
local sp = require "bee.subprocess"
Expand All @@ -274,8 +285,9 @@ function test_subprocess:test_filemode()
]], { stdin = true, stderr = true })
process.stdin:write "\r\n"
process.stdin:close()
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertEquals(process.stderr:read "a", "")
lt.assertEquals(process:detach(), true)
end

function test_subprocess:test_env()
Expand Down Expand Up @@ -313,25 +325,28 @@ function test_subprocess:test_setenv()
local process = shell:runlua([[
assert(os.getenv "TEST_ENV" == nil)
]], { stderr = true })
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertEquals(process.stderr:read "a", "")
lt.assertEquals(process:detach(), true)

subprocess.setenv("TEST_ENV", "OK")

lt.assertEquals(os.getenv "TEST_ENV", "OK")
local process = shell:runlua([[
assert(os.getenv "TEST_ENV" == "OK")
]], { stderr = true })
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertEquals(process.stderr:read "a", "")
lt.assertEquals(process:detach(), true)
end

function test_subprocess:test_encoding()
local process = shell:runlua([[
print "中文"
]], { stdout = true })
safe_exit(process)
lt.assertEquals(process:wait(), 0)
lt.assertEquals(process.stdout:read(6), "中文")
lt.assertEquals(process:detach(), true)
end

function test_subprocess:test_cwd()
Expand Down

0 comments on commit feedf28

Please sign in to comment.