kawauso_process/run/mod.rs
1//! The run of a command that the caller observes while it runs
2//!
3//! A run in one call reports after the command ended. An application that
4//! shows the progress of a command, or that turns the output of a command
5//! into events of its own, needs the output earlier. This module holds the
6//! handle that gives the output to such a caller, one line at a time, and the
7//! types of a line.
8//!
9//! The handle reports the same result as a run in one call, so an application
10//! that moves from the one form to the other keeps its handling of the
11//! result.
12
13pub mod line;
14pub mod stream;
15pub mod text;
16
17use std::collections::VecDeque;
18use std::future::Future;
19use std::future::poll_fn;
20use std::io::Error as IoError;
21#[cfg(unix)]
22use std::os::fd::AsFd;
23use std::pin::Pin;
24use std::pin::pin;
25use std::process::ExitStatus;
26use std::task::Context;
27use std::task::Poll;
28use std::time::Duration;
29use std::time::Instant;
30
31#[cfg(unix)]
32use rustix::io::Errno;
33#[cfg(unix)]
34use rustix::io::read;
35#[cfg(unix)]
36use rustix::process::Pid;
37#[cfg(unix)]
38use rustix::process::Signal;
39#[cfg(unix)]
40use rustix::process::kill_process;
41use tokio::io::AsyncRead;
42use tokio::io::ReadBuf;
43use tokio::process::Child;
44use tokio::process::ChildStderr;
45use tokio::process::ChildStdout;
46use tokio::time::timeout;
47
48pub use self::line::Line;
49pub use self::stream::Stream;
50pub use self::text::Text;
51use crate::error::RunCommandError;
52use crate::execution::Capture;
53use crate::execution::Execution;
54use crate::invocation::Invocation;
55use crate::process_id::ProcessId;
56
57/// The number of bytes that one read takes from a stream
58///
59/// The value is a compromise. A small buffer reads a stream in many steps,
60/// and a large one holds memory that most commands never fill, because a
61/// command writes lines and not blocks.
62const CHUNK: usize = 8 * 1024;
63
64/// The number of bytes that one take reads from a stream at most
65///
66/// A pipe of the operating system holds far less than this, so a command that
67/// ended left less than this in its stream. Bytes beyond this number come
68/// from a program that still writes. A take that follows such a program does
69/// not end.
70#[cfg(unix)]
71const LEFTOVER: usize = 4 * 1024 * 1024;
72
73/// The run of a command that the caller observes while it runs
74///
75/// The handle starts with the command and ends with the result of the run. It
76/// gives the output of the command to the caller as lines, in the order in
77/// which the lines arrive, and it collects the same capture that a run in one
78/// call collects. A caller that reads no line at all therefore still gets
79/// every byte that the command wrote.
80///
81/// The handle owns the command. A caller that drops the handle ends the
82/// command with it, so a timeout, a `select`, and a scheduler that abandons a
83/// run leave no process behind. The kill that ends such a command is
84/// immediate, and a caller that wants the command to end in good order calls
85/// [`stop`][stop] instead. A caller that waits for the end of the command in a
86/// `select` keeps the handle with [`wait_for_end`][wait-for-end].
87///
88/// # Examples
89///
90/// ```no_run
91/// use kawauso_process::Invocation;
92///
93/// # #[tokio::main(flavor = "current_thread")]
94/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
95/// let mut run = Invocation::new("cargo").arg("build").start()?;
96///
97/// while let Some(line) = run.next_line().await? {
98/// println!("[{}] {line}", line.stream());
99/// }
100///
101/// let execution = run.wait().await?.require_success()?;
102///
103/// println!("{}", execution.duration().as_secs());
104/// # Ok(())
105/// # }
106/// ```
107///
108/// [stop]: Run::stop
109/// [wait-for-end]: Run::wait_for_end
110#[derive(Debug)]
111pub struct Run {
112 /// The command that runs
113 ///
114 /// The handle carries it so that a log line and an error message can name
115 /// the command without the caller holding it a second time.
116 invocation: Invocation,
117
118 /// The command itself
119 child: Child,
120
121 /// The identifier that the operating system gave the command
122 ///
123 /// The handle records the value when the command starts. The crate can no
124 /// longer read the identifier after it collected the status of the
125 /// command. A caller can collect that status and keep the handle, so a
126 /// value that the handle read on demand is gone.
127 id: Option<ProcessId>,
128
129 /// The standard output of the command
130 stdout: Reader<ChildStdout>,
131
132 /// The standard error of the command
133 stderr: Reader<ChildStderr>,
134
135 /// The lines that the readers produced and the caller has not taken
136 ///
137 /// One read of a stream can produce more than one line, and the caller
138 /// takes one line per call. The queue holds the rest, in the order in
139 /// which the lines arrived.
140 lines: VecDeque<Line>,
141
142 /// The moment at which the command started
143 started: Instant,
144}
145
146impl Run {
147 /// Takes the streams of a command that started and builds the handle
148 ///
149 /// The constructor is not public, because it takes the command as the
150 /// asynchronous runtime represents it, and no public signature of this
151 /// crate names a type of that runtime. [`start`][start] is the way to a
152 /// handle.
153 ///
154 /// [start]: Invocation::start
155 pub(crate) fn new(invocation: Invocation, mut child: Child, started: Instant) -> Self {
156 // The command started with a pipe on each stream, so both are here.
157 // A reader without a stream reports the end of its stream at once,
158 // which leaves the caller with the streams that it can read.
159 let stdout = Reader::new(Stream::StandardOutput, child.stdout.take());
160 let stderr = Reader::new(Stream::StandardError, child.stderr.take());
161
162 // The command runs, so the operating system has given it an
163 // identifier. The handle takes the value now, because the crate can
164 // no longer read it after it collected the status of the command.
165 // process[impl run.identity]
166 let id = child.id().map(ProcessId::from);
167
168 Self {
169 invocation,
170 child,
171 id,
172 stdout,
173 stderr,
174 lines: VecDeque::new(),
175 started,
176 }
177 }
178
179 /// Reads the output of the command until both streams reached their end
180 ///
181 /// The capture grows with every read, so a drain fills it whether or not
182 /// the caller took a single line. The lines that no one took end here.
183 ///
184 /// # Errors
185 ///
186 /// Returns [`IncompleteRun`][incomplete] when a stream of the command
187 /// cannot be read.
188 ///
189 /// [incomplete]: RunCommandError::IncompleteRun
190 async fn drain(&mut self) -> Result<(), RunCommandError> {
191 while self.next_line().await?.is_some() {}
192
193 Ok(())
194 }
195
196 /// Reads the output of the command and collects its status
197 ///
198 /// The method is the work that every wait shares. It drains both streams
199 /// first. A command that fills a pipe stops until a reader empties it, and
200 /// such a command never reaches its own end.
201 ///
202 /// The crate collects the status of a command once, and this method
203 /// reports the same status on every call that follows.
204 ///
205 /// # Errors
206 ///
207 /// Returns [`IncompleteRun`][incomplete] when a stream of the command
208 /// cannot be read, or when the end of the command cannot be waited for.
209 ///
210 /// # Cancel safety
211 ///
212 /// The method is cancel safe. The drain is cancel safe, and the status of
213 /// the command lives in the command and not in the future of this call. A
214 /// caller that drops the future therefore loses no output and no status.
215 ///
216 /// [incomplete]: RunCommandError::IncompleteRun
217 async fn end(&mut self) -> Result<ExitStatus, RunCommandError> {
218 self.drain().await?;
219
220 self.child
221 .wait()
222 .await
223 .map_err(|source| RunCommandError::IncompleteRun {
224 invocation: Box::new(self.invocation.clone()),
225 source,
226 })
227 }
228
229 /// Waits for the exit of the command and reads both streams while it waits
230 ///
231 /// A command that fills a pipe stops until a reader empties it, so a wait
232 /// that reads nothing waits for a command that cannot end. The read
233 /// therefore runs with the wait, and the capture grows while the command
234 /// ends.
235 ///
236 /// The method returns as soon as the operating system reports the status
237 /// of the command. It does not wait for the end of the streams, which is
238 /// where it differs from [`end`][end]. A program that starts programs of
239 /// its own gives them its streams. Such a program can end while a program
240 /// that it started holds the streams open.
241 ///
242 /// # Errors
243 ///
244 /// Returns [`IncompleteRun`][incomplete] when a stream of the command
245 /// cannot be read, or when the end of the command cannot be waited for.
246 ///
247 /// [end]: Run::end
248 /// [incomplete]: RunCommandError::IncompleteRun
249 async fn exit(&mut self) -> Result<ExitStatus, RunCommandError> {
250 let Self {
251 invocation,
252 child,
253 stdout,
254 stderr,
255 lines,
256 ..
257 } = self;
258
259 // The wait holds its state in the future, so the method builds the
260 // future once and polls it again in every round.
261 let mut wait = pin!(child.wait());
262
263 let exited = poll_fn(|context| {
264 // The read comes first, because a command that fills a pipe ends
265 // only after something empties it.
266 let produced = match poll_streams(stdout, stderr, lines, context) {
267 Poll::Ready(Err(error)) => return Poll::Ready(Err(error)),
268 Poll::Ready(Ok(())) => true,
269 Poll::Pending => false,
270 };
271
272 if let Poll::Ready(exited) = wait.as_mut().poll(context) {
273 return Poll::Ready(exited);
274 }
275
276 // A stream that gave bytes registered no interest with the
277 // runtime, because it has nothing to wait for. The runtime
278 // therefore wakes nothing, and the call wakes itself instead.
279 if produced {
280 context.waker().wake_by_ref();
281 }
282
283 Poll::Pending
284 })
285 .await;
286
287 exited.map_err(|source| RunCommandError::IncompleteRun {
288 invocation: Box::new(invocation.clone()),
289 source,
290 })
291 }
292
293 /// Builds the result of a run that ended
294 ///
295 /// Every wait and the stop report the same result, and the method holds
296 /// the one place that builds it. The status arrives as an argument,
297 /// because the handle does not keep it.
298 fn finish(self, status: ExitStatus) -> Execution {
299 Execution::new(
300 self.invocation,
301 self.id,
302 status,
303 Capture::new(self.stdout.capture),
304 Capture::new(self.stderr.capture),
305 self.started.elapsed(),
306 )
307 }
308
309 /// Returns the identifier that the operating system gave the command
310 ///
311 /// An application that reports which program it started, or that gives
312 /// the command to a tool of the platform, reads the identifier here. The
313 /// handle records the value when the command starts, so the value is
314 /// there for the whole life of the handle. A wait for the end of the
315 /// command does not remove the value.
316 ///
317 /// The operating system takes the identifier of a command that ended, and
318 /// it can give the same identifier to another command. A caller that
319 /// waited for the end therefore reads the identifier of the command that
320 /// ran, and not the identifier of a command that runs.
321 ///
322 /// The value is `None` when the operating system gave the command no
323 /// identifier.
324 // process[impl stream.identity]
325 pub fn id(&self) -> Option<ProcessId> {
326 self.id
327 }
328
329 /// Returns the command that runs
330 pub fn invocation(&self) -> &Invocation {
331 &self.invocation
332 }
333
334 /// Kills the command without a request to end
335 ///
336 /// A kill that the operating system refuses names a process that it no
337 /// longer knows, which is a command that ended. The wait that follows
338 /// reports how the command ended, so the refusal tells the caller
339 /// nothing that the result does not carry.
340 fn kill(&mut self) {
341 let _ = self.child.start_kill();
342 }
343
344 /// Returns the next line of the output of the command
345 ///
346 /// The method waits until the command writes a line to one of its
347 /// streams, and it returns the lines in the order in which they arrive.
348 /// It returns `None` when the command closed both of its streams, which a
349 /// command does when it ends. A command that writes a last line without
350 /// the characters that end a line still reports that line.
351 ///
352 /// Every line that the method returns stays in the capture of the result
353 /// as well, so a caller that shows the output while the command runs and
354 /// then reports the whole output reads both from the same run.
355 ///
356 /// # Errors
357 ///
358 /// Returns [`IncompleteRun`][incomplete] when a stream of the command
359 /// cannot be read.
360 ///
361 /// # Cancel safety
362 ///
363 /// The method is cancel safe. A caller often waits for a line and for
364 /// another event, such as a timeout or another branch of a `select`. The
365 /// caller drops the future of the call when the other event occurs first,
366 /// and the call loses no output. The bytes that the call took stay with
367 /// the handle, and the call that follows reports the line that they
368 /// belong to.
369 ///
370 /// # Examples
371 ///
372 /// ```no_run
373 /// use kawauso_process::Invocation;
374 ///
375 /// # #[tokio::main(flavor = "current_thread")]
376 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
377 /// let mut run = Invocation::new("cargo").arg("test").start()?;
378 ///
379 /// while let Some(line) = run.next_line().await? {
380 /// println!("{line}");
381 /// }
382 /// # Ok(())
383 /// # }
384 /// ```
385 ///
386 /// [incomplete]: RunCommandError::IncompleteRun
387 // process[impl stream]
388 // process[impl stream.cancellation]
389 pub async fn next_line(&mut self) -> Result<Option<Line>, RunCommandError> {
390 loop {
391 if let Some(line) = self.lines.pop_front() {
392 return Ok(Some(line));
393 }
394
395 if self.stdout.is_closed() && self.stderr.is_closed() {
396 return Ok(None);
397 }
398
399 // A poll that takes bytes stores them in the reader and in the
400 // queue before it returns. The await point below is a poll that
401 // took nothing. Every state of the read therefore lives in the
402 // handle, and a future that the caller drops takes none of it.
403 let read = {
404 let Self {
405 stdout,
406 stderr,
407 lines,
408 ..
409 } = self;
410
411 poll_fn(|context| poll_streams(stdout, stderr, lines, context)).await
412 };
413
414 read.map_err(|source| RunCommandError::IncompleteRun {
415 invocation: Box::new(self.invocation.clone()),
416 source,
417 })?;
418 }
419 }
420
421 /// Asks the command to end, and reports whether the request went out
422 ///
423 /// A Unix platform has `SIGTERM`, which is the request that a program
424 /// answers when it ends its work in good order. The request reaches the
425 /// process of the command alone, and not a process group, so a command
426 /// that starts programs of its own decides what happens to them.
427 ///
428 /// A process that the operating system no longer knows, and a request
429 /// that it refuses, both report that nothing asked the command to end.
430 /// The stop then kills, because no answer can arrive.
431 ///
432 /// The method asks the operating system for the identifier of the
433 /// command, and it does not read the identifier that the handle reports.
434 /// The handle reports a recorded value, and the operating system can give
435 /// that identifier to another command after the command of this handle
436 /// ended. A request that reached that other command ends a program of
437 /// somebody else.
438 #[cfg(unix)]
439 fn request_end(&self) -> Request {
440 let Some(identifier) = self.child.id() else {
441 return Request::Unsent;
442 };
443
444 let Ok(identifier) = i32::try_from(identifier) else {
445 return Request::Unsent;
446 };
447
448 let Some(process) = Pid::from_raw(identifier) else {
449 return Request::Unsent;
450 };
451
452 match kill_process(process, Signal::TERM) {
453 Ok(()) => Request::Sent,
454 Err(_) => Request::Unsent,
455 }
456 }
457
458 /// Reports that this platform has no request to end
459 ///
460 /// Windows has no signal that asks a program to end its work, and the
461 /// crate has no interface of the operating system that takes its place.
462 /// The stop therefore kills the command at once, which the
463 /// documentation of the stop states.
464 #[cfg(not(unix))]
465 fn request_end(&self) -> Request {
466 Request::Unsent
467 }
468
469 /// Ends the command and reports the result of the run
470 ///
471 /// The method asks the command to end, and it gives the command the time
472 /// that the caller names. It kills a command that is still there when
473 /// the time is over. A program that answers the request removes its lock
474 /// file, writes what it has, and ends, which a kill gives it no time to
475 /// do.
476 ///
477 /// The request is `SIGTERM` on a Unix platform. A platform that has no
478 /// request of this kind kills the command at once, and the time then
479 /// passes unused. The request reaches the program that the crate
480 /// started, and not a group of processes, so a program that starts
481 /// programs of its own decides what happens to them.
482 ///
483 /// The time measures the command, and not the streams of the command. A
484 /// program that starts programs of its own gives them its streams. Such a
485 /// program can end while a program that it started holds the streams
486 /// open.
487 ///
488 /// The method reads both streams while it waits, so a command that fills
489 /// a pipe ends as well. It takes what the streams hold when the command
490 /// ends. On a Unix platform, a program that holds a stream open therefore
491 /// does not hold the call. On a platform that has no read of this kind,
492 /// the call waits for the end of both streams.
493 ///
494 /// The method reports what [`wait`][wait] reports: the exit status, the
495 /// capture of both streams, and the time that the run took.
496 ///
497 /// A caller that drops the handle instead of this call kills the command
498 /// at once, with no request before it.
499 ///
500 /// # Errors
501 ///
502 /// Returns [`IncompleteRun`][incomplete] when a stream of the command
503 /// cannot be read, or when the end of the command cannot be waited for.
504 ///
505 /// # Panics
506 ///
507 /// Panics when the Tokio runtime that drives the future has no timer.
508 /// The method waits for the time that the caller names, and the timer of
509 /// the runtime measures it.
510 ///
511 /// # Examples
512 ///
513 /// ```no_run
514 /// use std::time::Duration;
515 ///
516 /// use kawauso_process::Invocation;
517 ///
518 /// # #[tokio::main(flavor = "current_thread")]
519 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
520 /// let run = Invocation::new("cargo").arg("build").start()?;
521 ///
522 /// let execution = run.stop(Duration::from_secs(5)).await?;
523 ///
524 /// println!("{}", execution.status());
525 /// # Ok(())
526 /// # }
527 /// ```
528 ///
529 /// [incomplete]: RunCommandError::IncompleteRun
530 /// [wait]: Run::wait
531 // process[impl stop]
532 // process[impl stop.request]
533 pub async fn stop(mut self, grace: Duration) -> Result<Execution, RunCommandError> {
534 let exited = match self.request_end() {
535 // The command has the request, so it has the time to answer it.
536 // The wait reads what the command writes while it answers, so a
537 // command that fills a pipe reaches its own end.
538 // process[impl stop.grace]
539 // process[impl stop.bound]
540 Request::Sent => match timeout(grace, self.exit()).await {
541 Ok(exited) => Some(exited?),
542 Err(_) => None,
543 },
544
545 // Nothing asked the command to end, so nothing waits for an
546 // answer. The kill below is what this platform has.
547 Request::Unsent => None,
548 };
549
550 let status = match exited {
551 Some(status) => status,
552
553 // The command ignored the request, or nothing asked it to end.
554 // The kill ends it, and the wait that follows collects the status
555 // of a command that can no longer refuse.
556 // process[impl stop.kill]
557 None => {
558 self.kill();
559
560 self.exit().await?
561 }
562 };
563
564 // The command ended, and what it wrote last can still be in a pipe.
565 // process[impl stop.bound]
566 self.take().await?;
567
568 Ok(self.finish(status))
569 }
570
571 /// Reads what the streams of the command hold, and waits for nothing
572 ///
573 /// A command that ended wrote what it wrote, and the last of it can still
574 /// be in the pipe that carries a stream. The method takes those bytes, so
575 /// that the capture of the result holds them.
576 ///
577 /// The method waits for no stream. A program that the command started
578 /// inherits the streams of the command, and it holds them open for as
579 /// long as it runs. A read that waits for the end of such a stream waits
580 /// for a program that nothing asked to end.
581 ///
582 /// # Errors
583 ///
584 /// Returns [`IncompleteRun`][incomplete] when a stream of the command
585 /// cannot be read.
586 ///
587 /// [incomplete]: RunCommandError::IncompleteRun
588 #[cfg(unix)]
589 async fn take(&mut self) -> Result<(), RunCommandError> {
590 let Self {
591 invocation,
592 stdout,
593 stderr,
594 lines,
595 ..
596 } = self;
597
598 let taken = stdout.take(lines).and_then(|()| stderr.take(lines));
599
600 taken.map_err(|source| RunCommandError::IncompleteRun {
601 invocation: Box::new(invocation.clone()),
602 source,
603 })
604 }
605
606 /// Reads both streams of the command until they reached their end
607 ///
608 /// This platform has no read that reports what a stream holds without a
609 /// wait, so the method waits for the end of both streams. A program that
610 /// the command started inherits the streams, and it holds the call for as
611 /// long as it runs.
612 ///
613 /// # Errors
614 ///
615 /// Returns [`IncompleteRun`][incomplete] when a stream of the command
616 /// cannot be read.
617 ///
618 /// [incomplete]: RunCommandError::IncompleteRun
619 #[cfg(not(unix))]
620 async fn take(&mut self) -> Result<(), RunCommandError> {
621 self.drain().await
622 }
623
624 /// Waits for the end of the command and reports the result of the run
625 ///
626 /// The method reads what the command still writes, waits for the end of
627 /// the command, and reports what a run in one call reports: the exit
628 /// status, the capture of both streams, and the time that the run took.
629 /// The capture holds everything that the command wrote, whether or not
630 /// the caller read a line.
631 ///
632 /// A command that ends without success is no failure of this method. The
633 /// status travels in the result, and
634 /// [`require_success`][require-success] turns a status that is not a
635 /// success into an error.
636 ///
637 /// # Errors
638 ///
639 /// Returns [`IncompleteRun`][incomplete] when a stream of the command
640 /// cannot be read, or when the end of the command cannot be waited for.
641 ///
642 /// # Cancel safety
643 ///
644 /// The method is not cancel safe. It takes the handle, so a caller that
645 /// drops the future of a call ends the command. The caller loses the
646 /// result of the run, and the capture of both streams with it. A caller
647 /// that waits for the end of the command, and for an event of its own,
648 /// calls [`wait_for_end`][wait-for-end]. That method leaves the handle.
649 ///
650 /// # Examples
651 ///
652 /// ```no_run
653 /// use kawauso_process::Invocation;
654 ///
655 /// # #[tokio::main(flavor = "current_thread")]
656 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
657 /// let run = Invocation::new("cargo").arg("build").start()?;
658 ///
659 /// let execution = run.wait().await?;
660 ///
661 /// println!("{}", execution.status());
662 /// # Ok(())
663 /// # }
664 /// ```
665 ///
666 /// [incomplete]: RunCommandError::IncompleteRun
667 /// [require-success]: Execution::require_success
668 /// [wait-for-end]: Run::wait_for_end
669 // process[impl stream.wait]
670 pub async fn wait(mut self) -> Result<Execution, RunCommandError> {
671 let status = self.end().await?;
672
673 Ok(self.finish(status))
674 }
675
676 /// Waits for the end of the command and leaves the handle with the caller
677 ///
678 /// A caller often waits for the end of a command and for an event of its
679 /// own, such as a token that cancels the work. [`wait`][wait] takes the
680 /// handle, and this caller needs it. The caller holds nothing when the
681 /// event comes first, and [`stop`][stop] needs the handle. This method
682 /// reports the end of the command, and it leaves the handle. The caller
683 /// then asks for the result, or it stops a command that still runs.
684 ///
685 /// The method reports no result of its own. The handle keeps everything
686 /// that a result needs, so [`wait`][wait] reports the result after this
687 /// call. The wait that follows returns at once, because the command
688 /// ended.
689 ///
690 /// The method reads both streams while it waits, so a command that fills
691 /// a pipe ends as well. It waits for the command and not for the output
692 /// of the command. A command that closed both of its streams can still
693 /// run, and this method reports that end.
694 ///
695 /// # Errors
696 ///
697 /// Returns [`IncompleteRun`][incomplete] when a stream of the command
698 /// cannot be read, or when the end of the command cannot be waited for.
699 ///
700 /// # Cancel safety
701 ///
702 /// The method is cancel safe. The caller drops the future of the call
703 /// when the other event occurs first, and the command continues. The
704 /// handle keeps the output that the call read, and the caller stops the
705 /// command, takes the result, or waits again.
706 ///
707 /// # Examples
708 ///
709 /// ```no_run
710 /// use std::time::Duration;
711 ///
712 /// use kawauso_process::Invocation;
713 ///
714 /// # async fn cancelled() {}
715 /// # #[tokio::main(flavor = "current_thread")]
716 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
717 /// let mut run = Invocation::new("cargo").arg("build").start()?;
718 ///
719 /// let execution = tokio::select! {
720 /// ended = run.wait_for_end() => {
721 /// ended?;
722 /// run.wait().await?
723 /// }
724 /// () = cancelled() => run.stop(Duration::from_secs(5)).await?,
725 /// };
726 ///
727 /// println!("{}", execution.status());
728 /// # Ok(())
729 /// # }
730 /// ```
731 ///
732 /// [incomplete]: RunCommandError::IncompleteRun
733 /// [stop]: Run::stop
734 /// [wait]: Run::wait
735 // process[impl stream.end]
736 // process[impl stream.end.cancellation]
737 pub async fn wait_for_end(&mut self) -> Result<(), RunCommandError> {
738 self.end().await?;
739
740 Ok(())
741 }
742}
743
744/// Whether the request to end reached the command
745///
746/// A platform without a request of this kind, and a process that the
747/// operating system no longer knows, both leave the kill as the only way to
748/// end a run. A stop that asked nothing must not wait for an answer, because
749/// no answer can arrive.
750#[derive(Debug)]
751enum Request {
752 /// The command received the request to end
753 Sent,
754
755 /// Nothing asked the command to end
756 Unsent,
757}
758
759/// Reads the streams of a command until one of them produced something
760///
761/// The function polls both streams on every call, so a command that fills the
762/// pipe of one stream while it is quiet on the other never stops the run. A
763/// stream that produced nothing has registered its interest with the runtime,
764/// which wakes the caller when the stream has bytes.
765///
766/// The function returns `Pending` when both streams have nothing. A stream
767/// that reached its end reports nothing forever, so the caller stops before
768/// it calls this function with two such streams.
769///
770/// # Errors
771///
772/// Returns the error of the stream that could not be read.
773fn poll_streams(
774 stdout: &mut Reader<ChildStdout>,
775 stderr: &mut Reader<ChildStderr>,
776 lines: &mut VecDeque<Line>,
777 context: &mut Context<'_>,
778) -> Poll<Result<(), IoError>> {
779 let mut produced = false;
780
781 match stdout.poll(context, lines) {
782 Poll::Ready(Err(error)) => return Poll::Ready(Err(error)),
783 Poll::Ready(Ok(())) => produced = true,
784 Poll::Pending => {}
785 }
786
787 match stderr.poll(context, lines) {
788 Poll::Ready(Err(error)) => return Poll::Ready(Err(error)),
789 Poll::Ready(Ok(())) => produced = true,
790 Poll::Pending => {}
791 }
792
793 if produced {
794 Poll::Ready(Ok(()))
795 } else {
796 Poll::Pending
797 }
798}
799
800/// One stream of a command, with the capture and the line that it builds
801///
802/// The reader keeps three things apart. The capture holds every byte that the
803/// stream carried, because the result of the run reports the output as the
804/// command wrote it. The pending bytes hold the line that the command has
805/// started and not ended. The stream tells a line where it came from.
806#[derive(Debug)]
807struct Reader<S> {
808 /// The stream that this reader reads
809 stream: Stream,
810
811 /// The stream itself, and `None` after the stream reached its end
812 source: Option<S>,
813
814 /// The bytes of a line that the command has not ended
815 pending: Vec<u8>,
816
817 /// The number of pending bytes in which no end of a line was found
818 ///
819 /// A read looks for the end of a line in the bytes that it added, and not
820 /// in the bytes that it has looked at before. A command that writes a
821 /// long line therefore reads that line once, and not once per read.
822 searched: usize,
823
824 /// Every byte that the stream carried
825 capture: Vec<u8>,
826}
827
828impl<S: AsyncRead + Unpin> Reader<S> {
829 /// Creates the reader of one stream of a command
830 fn new(stream: Stream, source: Option<S>) -> Self {
831 Self {
832 stream,
833 source,
834 pending: Vec::new(),
835 searched: 0,
836 capture: Vec::new(),
837 }
838 }
839
840 /// Keeps the bytes of one read and builds the lines that they completed
841 fn accept(&mut self, read: &[u8], lines: &mut VecDeque<Line>) {
842 self.capture.extend_from_slice(read);
843 self.pending.extend_from_slice(read);
844 self.split(lines);
845 }
846
847 /// Marks the end of the stream and reports a line that has no end
848 ///
849 /// A command that wrote a last line without the characters that end a
850 /// line still wrote that line, because nothing follows it.
851 fn close(&mut self, lines: &mut VecDeque<Line>) {
852 self.source = None;
853
854 if !self.pending.is_empty() {
855 let bytes = std::mem::take(&mut self.pending);
856
857 self.searched = 0;
858 lines.push_back(self.line(&bytes));
859 }
860 }
861
862 /// Returns whether the stream reached its end
863 fn is_closed(&self) -> bool {
864 self.source.is_none()
865 }
866
867 /// Builds one line from the bytes that the command wrote
868 ///
869 /// A byte that is part of no valid character becomes the replacement
870 /// character, because a line is for a display and a display takes text.
871 /// The capture keeps the byte, so nothing that the command wrote is lost.
872 // process[impl stream.decode]
873 fn line(&self, bytes: &[u8]) -> Line {
874 Line::new(self.stream, String::from_utf8_lossy(bytes).into_owned())
875 }
876
877 /// Reads what the stream has and builds the lines that it completed
878 ///
879 /// The function returns `Ready` when it read bytes or when the stream
880 /// reached its end, and `Pending` when the stream has nothing yet. A
881 /// stream that reached its end reports `Pending`, because it has nothing
882 /// to report ever again.
883 ///
884 /// # Errors
885 ///
886 /// Returns the error of a stream that cannot be read.
887 fn poll(
888 &mut self,
889 context: &mut Context<'_>,
890 lines: &mut VecDeque<Line>,
891 ) -> Poll<Result<(), IoError>> {
892 let Some(source) = self.source.as_mut() else {
893 return Poll::Pending;
894 };
895
896 let mut bytes = [0; CHUNK];
897 let mut buffer = ReadBuf::new(&mut bytes);
898
899 match Pin::new(source).poll_read(context, &mut buffer) {
900 Poll::Pending => return Poll::Pending,
901 Poll::Ready(Err(error)) => return Poll::Ready(Err(error)),
902 Poll::Ready(Ok(())) => {}
903 }
904
905 let read = buffer.filled();
906
907 // A read of no bytes is the end of the stream.
908 if read.is_empty() {
909 self.close(lines);
910
911 return Poll::Ready(Ok(()));
912 }
913
914 self.accept(read, lines);
915
916 Poll::Ready(Ok(()))
917 }
918
919 /// Reads what the stream holds, and waits for nothing
920 ///
921 /// A read of a stream that holds no bytes reports that it found nothing,
922 /// and that ends the loop. The stream can be open at that moment: a
923 /// program that the command started inherited the stream, and it wrote
924 /// nothing. A program that writes without an end cannot hold the loop
925 /// either, because the loop reads no more than [`LEFTOVER`] bytes.
926 ///
927 /// The read goes to the stream itself, and not through the runtime. The
928 /// runtime reports a stream as quiet until it looked at the stream again,
929 /// and this call gives it no time to look.
930 ///
931 /// # Errors
932 ///
933 /// Returns the error of a stream that cannot be read.
934 #[cfg(unix)]
935 fn take(&mut self, lines: &mut VecDeque<Line>) -> Result<(), IoError>
936 where
937 S: AsFd,
938 {
939 let mut bytes = [0; CHUNK];
940 let mut taken = 0;
941
942 while taken < LEFTOVER {
943 let Some(source) = self.source.as_ref() else {
944 return Ok(());
945 };
946
947 match read(source, &mut bytes) {
948 Ok(0) => self.close(lines),
949 Ok(count) => {
950 taken += count;
951 self.accept(&bytes[..count], lines);
952 }
953
954 // A signal that arrived during the read took nothing from
955 // the stream, so the read starts again.
956 Err(Errno::INTR) => {}
957
958 // The stream is open and holds nothing, which is what ends
959 // this call.
960 Err(error) if error == Errno::AGAIN || error == Errno::WOULDBLOCK => {
961 return Ok(());
962 }
963
964 Err(error) => return Err(error.into()),
965 }
966 }
967
968 Ok(())
969 }
970
971 /// Takes every line that the command ended out of the pending bytes
972 ///
973 /// A command on Windows ends a line with two characters, and a command on
974 /// every other platform with one. The line carries neither of them, so a
975 /// caller that shows the line, or that compares it, reads the same text
976 /// on every platform.
977 // process[impl stream.crlf]
978 fn split(&mut self, lines: &mut VecDeque<Line>) {
979 while let Some(offset) = self.pending[self.searched..]
980 .iter()
981 .position(|byte| *byte == b'\n')
982 {
983 let end = self.searched + offset;
984 let mut bytes: Vec<u8> = self.pending.drain(..=end).collect();
985
986 bytes.pop();
987
988 if bytes.last() == Some(&b'\r') {
989 bytes.pop();
990 }
991
992 self.searched = 0;
993 lines.push_back(self.line(&bytes));
994 }
995
996 self.searched = self.pending.len();
997 }
998}
999
1000#[cfg(test)]
1001mod tests {
1002 // An assertion in a test panics by design. A `# Panics` section on every
1003 // test would repeat that and give the reader no information.
1004 #![allow(clippy::missing_panics_doc)]
1005
1006 use super::*;
1007
1008 // A caller keeps the handle in a task that another thread drives. This
1009 // test holds the type to the auto traits that make this possible, because
1010 // a private field of a later version could take them away without a word
1011 // from the compiler.
1012 #[test]
1013 fn run_is_send_and_sync() {
1014 fn assert_send_and_sync<T: Send + Sync>() {}
1015
1016 assert_send_and_sync::<Run>();
1017 }
1018}