mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
os: implement Process.set_work_folder/0 to set the initial working folder of the new child process (#17946)
This commit is contained in:
parent
489ac892b9
commit
c6947fde57
@ -28,6 +28,8 @@ mut:
|
||||
target Target
|
||||
omode Target
|
||||
is_verbose bool
|
||||
show_wd bool
|
||||
show_env bool
|
||||
}
|
||||
|
||||
fn (mut ctx Context) println(s string) {
|
||||
@ -53,7 +55,7 @@ fn main() {
|
||||
args := os.args[1..]
|
||||
if '-h' in args || '--help' in args {
|
||||
println("Usage:
|
||||
test_os_process [-v] [-h] [-target stderr/stdout/both/alternate] [-exitcode 0] [-timeout_ms 200] [-period_ms 50]
|
||||
test_os_process [-v] [-h] [-target stderr/stdout/both/alternate] [-show_wd] [-show_env] [-exitcode 0] [-timeout_ms 200] [-period_ms 50]
|
||||
Prints lines periodically (-period_ms), to stdout/stderr (-target).
|
||||
After a while (-timeout_ms), exit with (-exitcode).
|
||||
This program is useful for platform independent testing
|
||||
@ -63,6 +65,8 @@ fn main() {
|
||||
return
|
||||
}
|
||||
ctx.is_verbose = '-v' in args
|
||||
ctx.show_wd = '-show_wd' in args
|
||||
ctx.show_env = '-show_env' in args
|
||||
ctx.target = s2target(cmdline.option(args, '-target', 'both'))
|
||||
ctx.exitcode = cmdline.option(args, '-exitcode', '0').int()
|
||||
ctx.timeout_ms = cmdline.option(args, '-timeout_ms', '200').int()
|
||||
@ -73,6 +77,15 @@ fn main() {
|
||||
if ctx.is_verbose {
|
||||
eprintln('> args: ${args} | context: ${ctx}')
|
||||
}
|
||||
if ctx.show_wd {
|
||||
ctx.println('WORK_DIR=${os.getwd()}')
|
||||
}
|
||||
if ctx.show_env {
|
||||
all := os.environ()
|
||||
for k, v in all {
|
||||
ctx.println('${k}=${v}')
|
||||
}
|
||||
}
|
||||
spawn do_timeout(&ctx)
|
||||
for i := 1; true; i++ {
|
||||
ctx.println('${i}')
|
||||
|
@ -17,16 +17,16 @@ pub enum ProcessState {
|
||||
|
||||
[heap]
|
||||
pub struct Process {
|
||||
pub:
|
||||
filename string // the process's command file path
|
||||
pub mut:
|
||||
pid int // the PID of the process
|
||||
code int = -1
|
||||
filename string // the process's command file path
|
||||
pid int // the PID of the process
|
||||
code int = -1
|
||||
// the exit code of the process, != -1 *only* when status is .exited *and* the process was not aborted
|
||||
status ProcessState = .not_started
|
||||
// the current status of the process
|
||||
err string // if the process fails, contains the reason why
|
||||
args []string // the arguments that the command takes
|
||||
work_folder string // the initial working folder of the process. When '', reuse the same folder as the parent process.
|
||||
env_is_custom bool // true, when the environment was customized with .set_environment
|
||||
env []string // the environment with which the process was started (list of 'var=val')
|
||||
use_stdio_ctl bool // when true, then you can use p.stdin_write(), p.stdout_slurp() and p.stderr_slurp()
|
||||
@ -57,6 +57,16 @@ pub fn (mut p Process) set_args(pargs []string) {
|
||||
return
|
||||
}
|
||||
|
||||
// set_work_folder - set the initial working folder for the new process
|
||||
// If you do not set it, it will reuse the current working folder of the parent process.
|
||||
pub fn (mut p Process) set_work_folder(path string) {
|
||||
if p.status != .not_started {
|
||||
return
|
||||
}
|
||||
p.work_folder = real_path(path)
|
||||
return
|
||||
}
|
||||
|
||||
// set_environment - set a custom environment variable mapping for the new process
|
||||
pub fn (mut p Process) set_environment(envs map[string]string) {
|
||||
if p.status != .not_started {
|
||||
|
@ -50,6 +50,15 @@ fn (mut p Process) unix_spawn_process() int {
|
||||
fd_close(pipeset[3])
|
||||
fd_close(pipeset[5])
|
||||
}
|
||||
if p.work_folder != '' {
|
||||
if !is_abs_path(p.filename) {
|
||||
// Ensure p.filename contains an absolute path, so it
|
||||
// can be located reliably, even after changing the
|
||||
// current folder in the child process:
|
||||
p.filename = abs_path(p.filename)
|
||||
}
|
||||
chdir(p.work_folder) or {}
|
||||
}
|
||||
execve(p.filename, p.args, p.env) or {
|
||||
eprintln(err)
|
||||
exit(1)
|
||||
|
@ -36,6 +36,39 @@ fn test_getpid() {
|
||||
assert pid != 0
|
||||
}
|
||||
|
||||
fn test_set_work_folder() {
|
||||
new_work_folder := os.real_path(os.temp_dir())
|
||||
parent_working_folder := os.getwd()
|
||||
dump(new_work_folder)
|
||||
dump(parent_working_folder)
|
||||
if new_work_folder == parent_working_folder {
|
||||
eprintln('... skipping ${@METHOD} because the working folder is the temporary one')
|
||||
return
|
||||
}
|
||||
mut p := os.new_process(test_os_process)
|
||||
p.set_args(['-show_wd', '-target', 'stdout'])
|
||||
p.set_work_folder(new_work_folder)
|
||||
p.set_redirect_stdio()
|
||||
p.wait()
|
||||
assert p.code == 0
|
||||
output := p.stdout_slurp().trim_space()
|
||||
p.close()
|
||||
$if trace_process_output ? {
|
||||
eprintln('p output: "${output}"')
|
||||
}
|
||||
child_work_folder := output.find_between('stdout, WORK_DIR=', '\n').trim_space()
|
||||
dump(child_work_folder)
|
||||
assert child_work_folder == new_work_folder
|
||||
new_parent_work_folder := os.getwd()
|
||||
dump(new_parent_work_folder)
|
||||
assert new_parent_work_folder == parent_working_folder
|
||||
assert new_parent_work_folder != child_work_folder
|
||||
}
|
||||
|
||||
fn test_done() {
|
||||
exit(0)
|
||||
}
|
||||
|
||||
fn test_run() {
|
||||
mut p := os.new_process(test_os_process)
|
||||
p.set_args(['-timeout_ms', '150', '-period_ms', '50'])
|
||||
|
@ -57,7 +57,16 @@ pub mut:
|
||||
child_stderr_write &u32 = unsafe { nil }
|
||||
}
|
||||
|
||||
[manualfree]
|
||||
fn (mut p Process) win_spawn_process() int {
|
||||
mut to_be_freed := []voidptr{cap: 5}
|
||||
defer {
|
||||
for idx := to_be_freed.len - 1; idx >= 0; idx-- {
|
||||
unsafe { free(to_be_freed[idx]) }
|
||||
}
|
||||
unsafe { to_be_freed.free() }
|
||||
}
|
||||
p.filename = abs_path(p.filename) // expand the path to an absolute one, in case we later change the working folder
|
||||
mut wdata := &WProcess{
|
||||
child_stdin: 0
|
||||
child_stdout_read: 0
|
||||
@ -95,7 +104,9 @@ fn (mut p Process) win_spawn_process() int {
|
||||
start_info.dw_flags = u32(C.STARTF_USESTDHANDLES)
|
||||
}
|
||||
cmd := '${p.filename} ' + p.args.join(' ')
|
||||
C.ExpandEnvironmentStringsW(cmd.to_wide(), voidptr(&wdata.command_line[0]), 32768)
|
||||
cmd_wide_ptr := cmd.to_wide()
|
||||
to_be_freed << cmd_wide_ptr
|
||||
C.ExpandEnvironmentStringsW(cmd_wide_ptr, voidptr(&wdata.command_line[0]), 32768)
|
||||
|
||||
mut creation_flags := if p.create_no_window {
|
||||
int(C.CREATE_NO_WINDOW)
|
||||
@ -105,8 +116,15 @@ fn (mut p Process) win_spawn_process() int {
|
||||
if p.use_pgroup {
|
||||
creation_flags |= C.CREATE_NEW_PROCESS_GROUP
|
||||
}
|
||||
|
||||
mut work_folder_ptr := voidptr(unsafe { nil })
|
||||
if p.work_folder != '' {
|
||||
work_folder_ptr = p.work_folder.to_wide()
|
||||
to_be_freed << work_folder_ptr
|
||||
}
|
||||
|
||||
create_process_ok := C.CreateProcessW(0, &wdata.command_line[0], 0, 0, C.TRUE, creation_flags,
|
||||
0, 0, voidptr(&start_info), voidptr(&wdata.proc_info))
|
||||
0, work_folder_ptr, voidptr(&start_info), voidptr(&wdata.proc_info))
|
||||
failed_cfn_report_error(create_process_ok, 'CreateProcess')
|
||||
if p.use_stdio_ctl {
|
||||
close_valid_handle(&wdata.child_stdout_write)
|
||||
|
Loading…
Reference in New Issue
Block a user