-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsystem_command.v
More file actions
109 lines (101 loc) · 3.08 KB
/
Copy pathsystem_command.v
File metadata and controls
109 lines (101 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
module ruby
import os
import time
// CapturedCommandOptions isolates native process management from translated
// modules where a source `os` namespace shadows V's standard `os` module.
pub struct CapturedCommandOptions {
pub:
environment map[string]string
input string
chdir string
timeout ?time.Duration
use_pgroup bool
}
pub struct CapturedCommandResult {
pub:
exit_code int
stdout string
stderr string
}
pub fn environment() map[string]string {
return os.environ()
}
pub fn environment_value_opt(name string) ?string {
return os.getenv_opt(name)
}
pub fn absolute_path(path string) string {
return os.abs_path(path)
}
fn captured_command_temp_directory() string {
return os.join_path(os.temp_dir(), 'v-ruby-system-command-${os.getpid()}-${time.now().unix_nano()}')
}
// run_captured_command executes argv without interpolating it. The shell only
// installs file redirections; the executable and arguments remain positional
// parameters passed directly to `exec`.
pub fn run_captured_command(argv []string, options CapturedCommandOptions) !CapturedCommandResult {
if argv.len == 0 {
return error('command cannot be empty')
}
temporary_path := captured_command_temp_directory()
os.mkdir(temporary_path)!
defer {
os.rmdir_all(temporary_path) or {}
}
stdin_path := os.join_path(temporary_path, 'stdin')
stdout_path := os.join_path(temporary_path, 'stdout')
stderr_path := os.join_path(temporary_path, 'stderr')
os.write_file(stdin_path, options.input)!
os.write_file(stdout_path, '')!
os.write_file(stderr_path, '')!
mut process_environment := options.environment.clone()
process_environment['V_RUBY_SYSTEM_COMMAND_STDIN'] = stdin_path
process_environment['V_RUBY_SYSTEM_COMMAND_STDOUT'] = stdout_path
process_environment['V_RUBY_SYSTEM_COMMAND_STDERR'] = stderr_path
mut process := os.new_process('/bin/sh')
mut process_args := ['-c',
'exec "\$@" < "\$V_RUBY_SYSTEM_COMMAND_STDIN" > "\$V_RUBY_SYSTEM_COMMAND_STDOUT" 2> "\$V_RUBY_SYSTEM_COMMAND_STDERR"',
'v-ruby-system-command']
process_args << argv
process.set_args(process_args)
process.set_environment(process_environment)
if options.chdir != '' {
if !os.is_dir(options.chdir) {
return error('No such working directory: ${options.chdir}')
}
process.set_work_folder(options.chdir)
}
process.use_pgroup = options.use_pgroup
process.run()
if process.status == .aborted || process.err != '' {
message := process.err
process.close()
if message == '' {
return error('failed to start ${argv[0]}')
}
return error(message)
}
if timeout := options.timeout {
deadline := time.now().add(timeout)
for process.is_alive() && time.now() < deadline {
time.sleep(5 * time.millisecond)
}
if process.is_alive() {
if process.use_pgroup {
process.signal_pgkill()
} else {
process.signal_kill()
}
process.wait()
process.close()
return error('System command timed out: ${argv[0]}')
}
}
process.wait()
exit_code := process.code
process.close()
return CapturedCommandResult{
exit_code: exit_code
stdout: os.read_file(stdout_path)!
stderr: os.read_file(stderr_path)!
}
}