1use std::{
7 fmt,
8 ops::{Deref, DerefMut},
9};
10
11use tracing::{debug, info};
12
13use crate::{Command, Output, Result};
14
15#[derive(Clone, Debug, Default, Eq, PartialEq)]
20#[cfg_attr(
21 feature = "derive",
22 derive(serde::Serialize, serde::Deserialize),
23 serde(from = "Vec<String>", into = "Vec<String>")
24)]
25pub struct Pipeline(Vec<Command>);
26
27impl Pipeline {
28 pub fn new(cmds: impl IntoIterator<Item = impl ToString>) -> Self {
30 Self(cmds.into_iter().map(Command::new).collect())
31 }
32
33 pub fn replace(mut self, from: impl AsRef<str>, to: impl AsRef<str>) -> Self {
38 for cmd in self.iter_mut() {
39 *cmd = cmd.clone().replace(from.as_ref(), to.as_ref())
40 }
41
42 self
43 }
44
45 pub async fn run(&self) -> Result<Output> {
49 self.run_with([]).await
50 }
51
52 pub async fn run_with(&self, input: impl IntoIterator<Item = u8>) -> Result<Output> {
57 info!("run pipeline of {} commands", self.len());
58
59 let mut output: Vec<u8> = input.into_iter().collect();
60
61 for (i, cmd) in self.iter().enumerate() {
62 debug!("run command {} from pipeline", i + 1);
63 output = cmd.run_with(&output).await?.into();
64 }
65
66 Ok(Output::from(output))
67 }
68}
69
70impl Deref for Pipeline {
71 type Target = Vec<Command>;
72
73 fn deref(&self) -> &Self::Target {
74 &self.0
75 }
76}
77
78impl DerefMut for Pipeline {
79 fn deref_mut(&mut self) -> &mut Self::Target {
80 &mut self.0
81 }
82}
83
84impl From<Vec<Command>> for Pipeline {
85 fn from(cmds: Vec<Command>) -> Self {
86 Self(cmds)
87 }
88}
89
90impl From<Vec<String>> for Pipeline {
91 fn from(cmds: Vec<String>) -> Self {
92 Self(cmds.into_iter().map(Command::from).collect())
93 }
94}
95
96impl From<Pipeline> for Vec<String> {
97 fn from(pipeline: Pipeline) -> Self {
98 pipeline.iter().map(ToString::to_string).collect()
99 }
100}
101
102impl fmt::Display for Pipeline {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 let mut glue = "";
105
106 for cmd in self.iter() {
107 write!(f, "{glue}{}", cmd.to_string())?;
108 glue = " | ";
109 }
110
111 Ok(())
112 }
113}