@@ -36,7 +36,11 @@ async fn eval(command: &[String]) -> Result<ExitStatus> {
36
36
Ok ( child. wait ( ) . await ?)
37
37
}
38
38
39
- async fn run_task ( command : & [ String ] , task_timeout : Option < Duration > ) -> Result < TaskOutcome > {
39
+ async fn run_task (
40
+ command : & [ String ] ,
41
+ task_timeout : Option < Duration > ,
42
+ stop_on_exit_code : Option < i32 > ,
43
+ ) -> Result < TaskOutcome > {
40
44
let status_code = match task_timeout {
41
45
None => eval ( command) . await ?. code ( ) ,
42
46
Some ( task_timeout) => {
@@ -58,15 +62,25 @@ async fn run_task(command: &[String], task_timeout: Option<Duration>) -> Result<
58
62
if status_code == 0 {
59
63
return Ok ( TaskOutcome :: Success ) ;
60
64
}
65
+
66
+ if let Some ( exit_on_status_code) = stop_on_exit_code {
67
+ if status_code == exit_on_status_code {
68
+ return Ok ( TaskOutcome :: Success ) ;
69
+ }
70
+ }
61
71
}
62
72
63
73
Ok ( TaskOutcome :: Timeout )
64
74
}
65
75
66
- async fn loop_task ( command : & [ String ] , task_timeout : Option < Duration > ) -> Result < TaskOutcome > {
76
+ async fn loop_task (
77
+ command : & [ String ] ,
78
+ task_timeout : Option < Duration > ,
79
+ stop_on_exit_code : Option < i32 > ,
80
+ ) -> Result < TaskOutcome > {
67
81
loop {
68
- let status_code = run_task ( command, task_timeout) . await ?;
69
- if status_code == TaskOutcome :: Success {
82
+ let task_outcome = run_task ( command, task_timeout, stop_on_exit_code ) . await ?;
83
+ if task_outcome == TaskOutcome :: Success {
70
84
return Ok ( TaskOutcome :: Success ) ;
71
85
}
72
86
}
@@ -76,18 +90,22 @@ async fn run_tasks(
76
90
command : Vec < String > ,
77
91
up_to : Retry ,
78
92
task_timeout : Option < Duration > ,
93
+ stop_on_exit_code : Option < i32 > ,
79
94
) -> Result < ( ) > {
80
95
match up_to {
81
96
Retry :: ForDuration ( duration) => {
82
- let task_outcome =
83
- tokio:: time:: timeout ( duration, loop_task ( & command, task_timeout) ) . await ;
97
+ let task_outcome = tokio:: time:: timeout (
98
+ duration,
99
+ loop_task ( & command, task_timeout, stop_on_exit_code) ,
100
+ )
101
+ . await ;
84
102
if let Ok ( Ok ( TaskOutcome :: Success ) ) = task_outcome {
85
103
return Ok ( ( ) ) ;
86
104
}
87
105
}
88
106
Retry :: NumberOfTimes ( num_times) => {
89
107
for _ in 0 ..num_times {
90
- let task_outcome = run_task ( & command, task_timeout) . await ?;
108
+ let task_outcome = run_task ( & command, task_timeout, stop_on_exit_code ) . await ?;
91
109
if task_outcome == TaskOutcome :: Success {
92
110
return Ok ( ( ) ) ;
93
111
}
@@ -101,7 +119,13 @@ async fn run_tasks(
101
119
#[ tokio:: main]
102
120
async fn main ( ) -> Result < ( ) > {
103
121
let args: Cli = Cli :: parse ( ) ;
104
- run_tasks ( args. command , args. up_to , args. task_timeout ) . await
122
+ run_tasks (
123
+ args. command ,
124
+ args. up_to ,
125
+ args. task_timeout ,
126
+ args. stop_on_exit_code ,
127
+ )
128
+ . await
105
129
}
106
130
#[ cfg( test) ]
107
131
mod tests {
@@ -124,30 +148,30 @@ mod tests {
124
148
#[ tokio:: test]
125
149
async fn test_run_task_success ( ) {
126
150
let command = vec ! [ "true" . to_owned( ) ] ;
127
- let task_outcome = run_task ( & command, None ) . await . unwrap ( ) ;
151
+ let task_outcome = run_task ( & command, None , None ) . await . unwrap ( ) ;
128
152
assert_eq ! ( task_outcome, TaskOutcome :: Success ) ;
129
153
}
130
154
131
155
#[ tokio:: test]
132
156
async fn test_run_task_failure ( ) {
133
157
let command = vec ! [ "false" . to_owned( ) ] ;
134
- let task_outcome = run_task ( & command, None ) . await . unwrap ( ) ;
158
+ let task_outcome = run_task ( & command, None , None ) . await . unwrap ( ) ;
135
159
assert_eq ! ( task_outcome, TaskOutcome :: Timeout ) ;
136
160
}
137
161
138
162
#[ tokio:: test]
139
163
async fn test_run_task_timeout ( ) {
140
164
let command = vec ! [ "sleep" . to_owned( ) , "10" . to_owned( ) ] ;
141
165
let task_timeout = Some ( Duration :: from_secs ( 1 ) ) ;
142
- let task_outcome = run_task ( & command, task_timeout) . await . unwrap ( ) ;
166
+ let task_outcome = run_task ( & command, task_timeout, None ) . await . unwrap ( ) ;
143
167
assert_eq ! ( task_outcome, TaskOutcome :: Timeout ) ;
144
168
}
145
169
146
170
#[ tokio:: test]
147
171
async fn test_loop_task_success ( ) {
148
172
let command = vec ! [ "true" . to_owned( ) ] ;
149
173
let task_timeout = Some ( Duration :: from_secs ( 5 ) ) ;
150
- let task_outcome = loop_task ( & command, task_timeout) . await . unwrap ( ) ;
174
+ let task_outcome = loop_task ( & command, task_timeout, None ) . await . unwrap ( ) ;
151
175
assert_eq ! ( task_outcome, TaskOutcome :: Success ) ;
152
176
}
153
177
@@ -156,7 +180,7 @@ mod tests {
156
180
let command = vec ! [ "true" . to_owned( ) ] ;
157
181
let up_to = Retry :: NumberOfTimes ( 3 ) ;
158
182
let task_timeout = Some ( Duration :: from_secs ( 5 ) ) ;
159
- let result = run_tasks ( command, up_to, task_timeout) . await ;
183
+ let result = run_tasks ( command, up_to, task_timeout, None ) . await ;
160
184
assert_eq ! ( result. is_ok( ) , true ) ;
161
185
}
162
186
@@ -165,7 +189,7 @@ mod tests {
165
189
let command = vec ! [ "false" . to_owned( ) ] ;
166
190
let up_to = Retry :: NumberOfTimes ( 3 ) ;
167
191
let task_timeout = Some ( Duration :: from_secs ( 5 ) ) ;
168
- let result = run_tasks ( command, up_to, task_timeout) . await ;
192
+ let result = run_tasks ( command, up_to, task_timeout, None ) . await ;
169
193
assert_eq ! ( result. is_err( ) , true ) ;
170
194
}
171
195
@@ -174,7 +198,22 @@ mod tests {
174
198
let command = vec ! [ "sleep" . to_owned( ) , "10" . to_owned( ) ] ;
175
199
let up_to = Retry :: ForDuration ( Duration :: from_secs ( 5 ) ) ;
176
200
let task_timeout = Some ( Duration :: from_secs ( 1 ) ) ;
177
- let result = run_tasks ( command, up_to, task_timeout) . await ;
201
+ let result = run_tasks ( command, up_to, task_timeout, None ) . await ;
178
202
assert_eq ! ( result. is_err( ) , true ) ;
179
203
}
204
+
205
+ #[ tokio:: test]
206
+ async fn test_run_tasks_stop_on_exit_code ( ) {
207
+ let command = vec ! [
208
+ "bash" . to_string( ) ,
209
+ "-c" . to_string( ) ,
210
+ "\" exit\" " . to_string( ) ,
211
+ "\" 2\" " . to_string( ) ,
212
+ ] ;
213
+ let up_to = Retry :: NumberOfTimes ( 5 ) ;
214
+ let task_timeout = Some ( Duration :: from_secs ( 5 ) ) ;
215
+ let stop_on_exit_code = Some ( 2 ) ;
216
+ let result = run_tasks ( command, up_to, task_timeout, stop_on_exit_code) . await ;
217
+ assert_eq ! ( result. is_ok( ) , true ) ;
218
+ }
180
219
}
0 commit comments