6 Commits
9 changed files with 68 additions and 77 deletions
+1 -2
View File
@@ -9,7 +9,7 @@ but I don't like any of them. So let's overview.
* `os.execvp()`, `os.execve()` — cross-platform versions of the C functions of the same name. * `os.execvp()`, `os.execve()` — cross-platform versions of the C functions of the same name.
* `os.execute()`, `os.execute_opt()`, `os.execute_or_exit()`, `os.execute_or_panic()` — starts and waits for a command to completed. Under the hood, they perform a dirty hack by calling shell with stream redirection `'exec 2>&1;${cmd}'`. * `os.execute()`, `os.execute_opt()`, `os.execute_or_exit()`, `os.execute_or_panic()`, `os.raw_execute()` — starts and waits for a command to completed. Under the hood, they perform a dirty hack by calling shell with stream redirection `'exec 2>&1;${cmd}'`.
* `util.execute_with_timeout()` (from `os.util`) — just an `os.execute()` wrapper. * `util.execute_with_timeout()` (from `os.util`) — just an `os.execute()` wrapper.
@@ -55,7 +55,6 @@ directory. **Examples are very important**.
- [x] Basic implementation. - [x] Basic implementation.
- [x] Contexts support for creating cancelable commands, commands with timeouts, etc. - [x] Contexts support for creating cancelable commands, commands with timeouts, etc.
- [ ] Process groups support, pgkill().
- [ ] Better error handling and more tests... - [ ] Better error handling and more tests...
Send pull requests for additional features/bugfixes. Send pull requests for additional features/bugfixes.
-26
View File
@@ -1,26 +0,0 @@
module runcmd
import io
// buffer creates simple bytes buffer that can be read through `io.Reader` interface.
pub fn buffer(data []u8) ByteBuffer {
return ByteBuffer{
bytes: data
}
}
struct ByteBuffer {
bytes []u8
mut:
pos int
}
// read reads `buf.len` bytes from internal bytes buffer and returns number of bytes read.
pub fn (mut b ByteBuffer) read(mut buf []u8) !int {
if b.pos >= b.bytes.len {
return io.Eof{}
}
n := copy(mut buf, b.bytes[b.pos..])
b.pos += n
return n
}
+1 -1
View File
@@ -268,7 +268,7 @@ pub fn (mut c Command) start() !int {
path: path path: path
argv: c.args argv: c.args
env: if c.env.len == 0 { os.environ() } else { c.env } env: if c.env.len == 0 { os.environ() } else { c.env }
dir: c.dir dir: os.abs_path(c.dir)
post_fork: [parent_pipes_hook] post_fork: [parent_pipes_hook]
pre_exec: pre_exec_hooks pre_exec: pre_exec_hooks
} }
+4 -2
View File
@@ -1,4 +1,4 @@
import io.string_reader import io
import rand import rand
import runcmd import runcmd
import time import time
@@ -20,7 +20,7 @@ fn main() {
mut child_stdout := cmd.stdout()! mut child_stdout := cmd.stdout()!
// Prepare reader to store command output. // Prepare reader to store command output.
mut output := string_reader.StringReader.new(reader: child_stdout) mut output := io.new_buffered_reader(reader: child_stdout)
// Start stdout reading in a coroutine. // Start stdout reading in a coroutine.
// //
@@ -56,4 +56,6 @@ fn main() {
// wait() will close the child stdout file desciptor by itself. // wait() will close the child stdout file desciptor by itself.
cmd.wait()! cmd.wait()!
println('Child state: ${cmd.state}')
} }
+2 -2
View File
@@ -1,4 +1,4 @@
import io.string_reader import io
import runcmd import runcmd
fn main() { fn main() {
@@ -14,7 +14,7 @@ fn main() {
// Setup StringReader with stdout input. Note the cmd.stdout()! call, it // Setup StringReader with stdout input. Note the cmd.stdout()! call, it
// returns the io.Reader interface and reads child process stdout file descriptor. // returns the io.Reader interface and reads child process stdout file descriptor.
mut reader := string_reader.StringReader.new(reader: cmd.stdout()!) mut reader := io.new_buffered_reader(reader: cmd.stdout()!)
// Read sdtout line by line until EOF. // Read sdtout line by line until EOF.
for { for {
+21 -2
View File
@@ -1,6 +1,23 @@
import io
import strings import strings
import runcmd import runcmd
struct ByteBuffer {
bytes []u8
mut:
pos int
}
// read reads `buf.len` bytes from internal bytes buffer and returns number of bytes read.
pub fn (mut b ByteBuffer) read(mut buf []u8) !int {
if b.pos >= b.bytes.len {
return io.Eof{}
}
n := copy(mut buf, b.bytes[b.pos..])
b.pos += n
return n
}
fn main() { fn main() {
input := 'Hello from parent process!' input := 'Hello from parent process!'
@@ -8,8 +25,10 @@ fn main() {
// * `reader` reads input from the parent process; it will be copied to the // * `reader` reads input from the parent process; it will be copied to the
// standard input of the child process. // standard input of the child process.
// * `writer` accepts data from the child process; it will be copied from the // * `writer` accepts data from the child process; it will be copied from the
// standard output of the child process. // standard output of the child process. This is optinal.
mut reader := runcmd.buffer(input.bytes()) mut reader := ByteBuffer{
bytes: input.bytes()
}
mut writer := strings.new_builder(4096) mut writer := strings.new_builder(4096)
// Prepare the command. // Prepare the command.
+10 -9
View File
@@ -76,19 +76,20 @@ pub fn (s ProcessState) str() string {
sig_str := os.sigint_to_signal_name(sig) sig_str := os.sigint_to_signal_name(sig)
str = 'signal: ${sig} (${sig_str})' str = 'signal: ${sig} (${sig_str})'
} }
s.status.stopped() { // s.status.stopped() {
str = 'stop signal: ${s.status.stop_signal()}' // str = 'stop signal: ${s.status.stop_signal()}'
} // }
s.status.continued() { // s.status.continued() {
str = 'continued' // str = 'continued'
} // }
else { else {
str = 'unknown' str = 'unknown'
} }
} }
if s.status.coredump() {
str += ' (core dumped)' // if s.status.coredump() {
} // str += ' (core dumped)'
// }
return str return str
} }
+1 -1
View File
@@ -1,7 +1,7 @@
Module { Module {
name: 'runcmd' name: 'runcmd'
description: 'Run external commands' description: 'Run external commands'
version: '0.3.0' version: '0.4.0'
license: 'Unlicense' license: 'Unlicense'
repo_url: 'https://github.com/gechandesu/runcmd' repo_url: 'https://github.com/gechandesu/runcmd'
dependencies: [] dependencies: []
+28 -32
View File
@@ -1,19 +1,15 @@
module runcmd module runcmd
@[trusted] // fn C.WIFSTOPPED(i32) bool
fn C.WIFSTOPPED(int) bool
@[trusted] // fn C.WCOREDUMP(i32) bool
fn C.WCOREDUMP(int) bool
@[trusted] // fn C.WIFCONTINUED(i32) bool
fn C.WIFCONTINUED(int) bool
@[trusted] // fn C.WSTOPSIG(i32) int
fn C.WSTOPSIG(int) int
// WaitStatus stores the result value of [wait(2)](https://www.man7.org/linux/man-pages/man2/wait.2.html) syscall. // WaitStatus stores the result value of [wait(2)](https://www.man7.org/linux/man-pages/man2/wait.2.html) syscall.
pub type WaitStatus = u32 pub type WaitStatus = int
// exited returns true if process is exited. // exited returns true if process is exited.
pub fn (w WaitStatus) exited() bool { pub fn (w WaitStatus) exited() bool {
@@ -41,29 +37,29 @@ pub fn (w WaitStatus) term_signal() int {
return -1 return -1
} }
// stopped returns true if the child process was stopped by delivery of a signal. // // stopped returns true if the child process was stopped by delivery of a signal.
pub fn (w WaitStatus) stopped() bool { // pub fn (w WaitStatus) stopped() bool {
return C.WIFSTOPPED(w) // return C.WIFSTOPPED(w)
} // }
// stop_signal returns the number of the signal which caused the child to stop. // // stop_signal returns the number of the signal which caused the child to stop.
pub fn (w WaitStatus) stop_signal() int { // pub fn (w WaitStatus) stop_signal() int {
if w.stopped() { // if w.stopped() {
return C.WSTOPSIG(w) // return C.WSTOPSIG(w)
} // }
return -1 // return -1
} // }
// continued returns true if the child process was resumed by delivery of SIGCONT. // // continued returns true if the child process was resumed by delivery of SIGCONT.
pub fn (w WaitStatus) continued() bool { // pub fn (w WaitStatus) continued() bool {
return C.WIFCONTINUED(w) // return C.WIFCONTINUED(w)
} // }
// coredump returns true if the child produced a core dump. // // coredump returns true if the child produced a core dump.
// See [core(5)](https://man7.org/linux/man-pages/man5/core.5.html). // // See [core(5)](https://man7.org/linux/man-pages/man5/core.5.html).
pub fn (w WaitStatus) coredump() bool { // pub fn (w WaitStatus) coredump() bool {
if w.signaled() { // if w.signaled() {
return C.WCOREDUMP(w) // return C.WCOREDUMP(w)
} // }
return false // return false
} // }