@@ -30,7 +30,10 @@ pub use self::child::{Child, ChildExit};
30
30
/// using `spawn`. When the manager is Closed, all currently-running children
31
31
/// will be closed, and no new children can be spawned.
32
32
#[ derive( Debug , Clone ) ]
33
- pub struct ProcessManager ( Arc < Mutex < ProcessManagerInner > > ) ;
33
+ pub struct ProcessManager {
34
+ state : Arc < Mutex < ProcessManagerInner > > ,
35
+ use_pty : bool ,
36
+ }
34
37
35
38
#[ derive( Debug ) ]
36
39
struct ProcessManagerInner {
@@ -39,11 +42,22 @@ struct ProcessManagerInner {
39
42
}
40
43
41
44
impl ProcessManager {
42
- pub fn new ( ) -> Self {
43
- Self ( Arc :: new ( Mutex :: new ( ProcessManagerInner {
44
- is_closing : false ,
45
- children : Vec :: new ( ) ,
46
- } ) ) )
45
+ pub fn new ( use_pty : bool ) -> Self {
46
+ Self {
47
+ state : Arc :: new ( Mutex :: new ( ProcessManagerInner {
48
+ is_closing : false ,
49
+ children : Vec :: new ( ) ,
50
+ } ) ) ,
51
+ use_pty,
52
+ }
53
+ }
54
+
55
+ /// Construct a process manager and infer if pty should be used
56
+ pub fn infer ( ) -> Self {
57
+ // Only use PTY if we're not on windows and we're currently hooked up to a
58
+ // in a TTY
59
+ let use_pty = !cfg ! ( windows) && atty:: is ( atty:: Stream :: Stdout ) ;
60
+ Self :: new ( use_pty)
47
61
}
48
62
}
49
63
@@ -61,17 +75,14 @@ impl ProcessManager {
61
75
command : Command ,
62
76
stop_timeout : Duration ,
63
77
) -> Option < io:: Result < child:: Child > > {
64
- let mut lock = self . 0 . lock ( ) . unwrap ( ) ;
78
+ let mut lock = self . state . lock ( ) . unwrap ( ) ;
65
79
if lock. is_closing {
66
80
return None ;
67
81
}
68
- // Only use PTY if we're not on windows and we're currently hooked up to a
69
- // in a TTY
70
- let use_pty = !cfg ! ( windows) && atty:: is ( atty:: Stream :: Stdout ) ;
71
82
let child = child:: Child :: spawn (
72
83
command,
73
84
child:: ShutdownStyle :: Graceful ( stop_timeout) ,
74
- use_pty,
85
+ self . use_pty ,
75
86
) ;
76
87
if let Ok ( child) = & child {
77
88
lock. children . push ( child. clone ( ) ) ;
@@ -108,7 +119,7 @@ impl ProcessManager {
108
119
let mut set = JoinSet :: new ( ) ;
109
120
110
121
{
111
- let mut lock = self . 0 . lock ( ) . expect ( "not poisoned" ) ;
122
+ let mut lock = self . state . lock ( ) . expect ( "not poisoned" ) ;
112
123
lock. is_closing = true ;
113
124
for child in lock. children . iter ( ) {
114
125
let child = child. clone ( ) ;
@@ -123,7 +134,7 @@ impl ProcessManager {
123
134
}
124
135
125
136
{
126
- let mut lock = self . 0 . lock ( ) . expect ( "not poisoned" ) ;
137
+ let mut lock = self . state . lock ( ) . expect ( "not poisoned" ) ;
127
138
128
139
// just allocate a new vec rather than clearing the old one
129
140
lock. children = vec ! [ ] ;
@@ -155,7 +166,7 @@ mod test {
155
166
156
167
#[ tokio:: test]
157
168
async fn test_basic ( ) {
158
- let manager = ProcessManager :: new ( ) ;
169
+ let manager = ProcessManager :: new ( false ) ;
159
170
let mut child = manager
160
171
. spawn ( get_script_command ( "hello_world.js" ) , Duration :: from_secs ( 2 ) )
161
172
. unwrap ( )
@@ -168,7 +179,7 @@ mod test {
168
179
169
180
#[ tokio:: test]
170
181
async fn test_multiple ( ) {
171
- let manager = ProcessManager :: new ( ) ;
182
+ let manager = ProcessManager :: new ( false ) ;
172
183
173
184
let children = ( 0 ..2 )
174
185
. map ( |_| {
@@ -191,7 +202,7 @@ mod test {
191
202
192
203
#[ tokio:: test]
193
204
async fn test_closed ( ) {
194
- let manager = ProcessManager :: new ( ) ;
205
+ let manager = ProcessManager :: new ( false ) ;
195
206
let mut child = manager
196
207
. spawn ( get_command ( ) , Duration :: from_secs ( 2 ) )
197
208
. unwrap ( )
@@ -218,7 +229,7 @@ mod test {
218
229
219
230
#[ tokio:: test]
220
231
async fn test_exit_code ( ) {
221
- let manager = ProcessManager :: new ( ) ;
232
+ let manager = ProcessManager :: new ( false ) ;
222
233
let mut child = manager
223
234
. spawn ( get_script_command ( "hello_world.js" ) , Duration :: from_secs ( 2 ) )
224
235
. unwrap ( )
@@ -235,7 +246,7 @@ mod test {
235
246
#[ tokio:: test]
236
247
#[ traced_test]
237
248
async fn test_message_after_stop ( ) {
238
- let manager = ProcessManager :: new ( ) ;
249
+ let manager = ProcessManager :: new ( false ) ;
239
250
let mut child = manager
240
251
. spawn ( get_script_command ( "hello_world.js" ) , Duration :: from_secs ( 2 ) )
241
252
. unwrap ( )
@@ -258,14 +269,14 @@ mod test {
258
269
259
270
#[ tokio:: test]
260
271
async fn test_reuse_manager ( ) {
261
- let manager = ProcessManager :: new ( ) ;
272
+ let manager = ProcessManager :: new ( false ) ;
262
273
manager. spawn ( get_command ( ) , Duration :: from_secs ( 2 ) ) ;
263
274
264
275
sleep ( Duration :: from_millis ( 100 ) ) . await ;
265
276
266
277
manager. stop ( ) . await ;
267
278
268
- assert ! ( manager. 0 . lock( ) . unwrap( ) . children. is_empty( ) ) ;
279
+ assert ! ( manager. state . lock( ) . unwrap( ) . children. is_empty( ) ) ;
269
280
270
281
// TODO: actually do some check that this is idempotent
271
282
// idempotent
@@ -280,7 +291,7 @@ mod test {
280
291
script : & str ,
281
292
expected : Option < ChildExit > ,
282
293
) {
283
- let manager = ProcessManager :: new ( ) ;
294
+ let manager = ProcessManager :: new ( false ) ;
284
295
let tasks = FuturesUnordered :: new ( ) ;
285
296
286
297
for _ in 0 ..10 {
@@ -315,7 +326,7 @@ mod test {
315
326
316
327
#[ tokio:: test]
317
328
async fn test_wait_multiple_tasks ( ) {
318
- let manager = ProcessManager :: new ( ) ;
329
+ let manager = ProcessManager :: new ( false ) ;
319
330
320
331
let mut out = Vec :: new ( ) ;
321
332
let mut child = manager
0 commit comments