1 # Functions for running system commands
5 enum ExitType(Exited(status:Int32), Signaled(signal:Int32), Failed)
6 func succeeded(e:ExitType -> Bool)
7 when e is Exited(status) return (status == 0)
10 func or_fail(e:ExitType, message:Text?=none)
12 fail(message or "Program failed: $e")
14 struct ProgramResult(output:[Byte], errors:[Byte], exit_type:ExitType)
15 func or_fail(r:ProgramResult, message:Text?=none -> ProgramResult)
16 when r.exit_type is Exited(status)
18 fail(message or "Program failed: $r")
19 else fail(message or "Program failed: $r")
22 func output_text(r:ProgramResult, trim_newline=yes -> Text?)
23 when r.exit_type is Exited(status)
25 if text := Text.from_utf8(r.output)
27 text = text.without_suffix("\n")
32 func error_text(r:ProgramResult -> Text?)
33 when r.exit_type is Exited(status)
35 return Text.from_utf8(r.errors)
39 func succeeded(r:ProgramResult -> Bool)
40 when r.exit_type is Exited(status)
45 struct Command(command:Text, args:[Text]=[], env:{Text=Text}={})
46 func from_path(path:Path, args:[Text]=[], env:{Text=Text}={} -> Command)
47 return Command(Text(path), args, env)
49 func result(command:Command, input="", input_bytes:[Byte]=[] -> ProgramResult)
51 (&input_bytes).insert_all(input.utf8())
55 status := C_code:Int32`
56 run_command(@(command.command), @(command.args), @(command.env), @input_bytes, &@output, &@errors)
59 if C_code:Bool`WIFEXITED(@status)`
60 return ProgramResult(output, errors, ExitType.Exited(C_code:Int32`WEXITSTATUS(@status)`))
62 if C_code:Bool`WIFSIGNALED(@status)`
63 return ProgramResult(output, errors, ExitType.Signaled(C_code:Int32`WTERMSIG(@status)`))
65 return ProgramResult(output, errors, ExitType.Failed)
67 func run(command:Command, -> ExitType)
68 status := C_code:Int32`
69 run_command(@(command.command), @(command.args), @(command.env), NONE_LIST, NULL, NULL)
72 if C_code:Bool`WIFEXITED(@status)`
73 return ExitType.Exited(C_code:Int32`WEXITSTATUS(@status)`)
75 if C_code:Bool`WIFSIGNALED(@status)`
76 return ExitType.Signaled(C_code:Int32`WTERMSIG(@status)`)
78 return ExitType.Failed
80 func get_output(command:Command, input="", trim_newline=yes -> Text?)
81 return command.result(input=input).output_text(trim_newline=trim_newline)
83 func get_output_bytes(command:Command, input="", input_bytes:[Byte]=[] -> [Byte]?)
84 result := command.result(input=input, input_bytes=input_bytes)
85 when result.exit_type is Exited(status)
86 if status == 0 return result.output
90 func by_line(command:Command -> func(->Text?)?)
91 return C_code:func(->Text?)?`
92 command_by_line(@(command.command), @(command.args), @(command.env))
95 func main(cmd:Command)