terraform_wrapper/commands/
show.rs1use crate::Terraform;
2use crate::command::TerraformCommand;
3use crate::error::Result;
4use crate::exec;
5
6#[derive(Debug, Clone)]
13pub enum ShowResult {
14 #[cfg(feature = "json")]
16 State(crate::types::state::StateRepresentation),
17 #[cfg(feature = "json")]
19 Plan(Box<crate::types::plan::PlanRepresentation>),
20 Plain(exec::CommandOutput),
22}
23
24#[derive(Debug, Clone, Default)]
48pub struct ShowCommand {
49 plan_file: Option<String>,
50 json: bool,
51 raw_args: Vec<String>,
52}
53
54impl ShowCommand {
55 #[must_use]
57 pub fn new() -> Self {
58 Self {
59 json: true,
60 ..Self::default()
61 }
62 }
63
64 #[must_use]
66 pub fn plan_file(mut self, path: &str) -> Self {
67 self.plan_file = Some(path.to_string());
68 self
69 }
70
71 #[must_use]
73 pub fn no_json(mut self) -> Self {
74 self.json = false;
75 self
76 }
77
78 #[must_use]
80 pub fn arg(mut self, arg: impl Into<String>) -> Self {
81 self.raw_args.push(arg.into());
82 self
83 }
84}
85
86impl TerraformCommand for ShowCommand {
87 type Output = ShowResult;
88
89 fn args(&self) -> Vec<String> {
90 let mut args = vec!["show".to_string()];
91 if self.json {
92 args.push("-json".to_string());
93 }
94 args.extend(self.raw_args.clone());
95 if let Some(ref plan) = self.plan_file {
97 args.push(plan.clone());
98 }
99 args
100 }
101
102 async fn execute(&self, tf: &Terraform) -> Result<ShowResult> {
103 let output = exec::run_terraform(tf, self.args()).await?;
104
105 if !self.json {
106 return Ok(ShowResult::Plain(output));
107 }
108
109 #[cfg(feature = "json")]
110 if self.plan_file.is_some() {
111 let plan: crate::types::plan::PlanRepresentation = serde_json::from_str(&output.stdout)
112 .map_err(|e| crate::error::Error::Json {
113 message: "failed to parse plan json".to_string(),
114 source: e,
115 })?;
116 return Ok(ShowResult::Plan(Box::new(plan)));
117 }
118
119 #[cfg(feature = "json")]
120 {
121 let state: crate::types::state::StateRepresentation =
122 serde_json::from_str(&output.stdout).map_err(|e| crate::error::Error::Json {
123 message: "failed to parse state json".to_string(),
124 source: e,
125 })?;
126 Ok(ShowResult::State(state))
127 }
128
129 #[cfg(not(feature = "json"))]
130 Ok(ShowResult::Plain(output))
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn default_args_include_json() {
140 let cmd = ShowCommand::new();
141 assert_eq!(cmd.args(), vec!["show", "-json"]);
142 }
143
144 #[test]
145 fn plan_file_at_end() {
146 let cmd = ShowCommand::new().plan_file("tfplan");
147 assert_eq!(cmd.args(), vec!["show", "-json", "tfplan"]);
148 }
149
150 #[test]
151 fn no_json_args() {
152 let cmd = ShowCommand::new().no_json();
153 assert_eq!(cmd.args(), vec!["show"]);
154 }
155
156 #[test]
157 fn no_json_with_plan_file() {
158 let cmd = ShowCommand::new().no_json().plan_file("tfplan");
159 assert_eq!(cmd.args(), vec!["show", "tfplan"]);
160 }
161}