use crate::Terraform;
use crate::command::TerraformCommand;
use crate::error::Result;
use crate::exec;
#[derive(Debug, Clone)]
pub enum ShowResult {
#[cfg(feature = "json")]
State(crate::types::state::StateRepresentation),
#[cfg(feature = "json")]
Plan(Box<crate::types::plan::PlanRepresentation>),
Plain(exec::CommandOutput),
}
#[derive(Debug, Clone, Default)]
pub struct ShowCommand {
plan_file: Option<String>,
json: bool,
raw_args: Vec<String>,
}
impl ShowCommand {
#[must_use]
pub fn new() -> Self {
Self {
json: true,
..Self::default()
}
}
#[must_use]
pub fn plan_file(mut self, path: &str) -> Self {
self.plan_file = Some(path.to_string());
self
}
#[must_use]
pub fn no_json(mut self) -> Self {
self.json = false;
self
}
#[must_use]
pub fn arg(mut self, arg: impl Into<String>) -> Self {
self.raw_args.push(arg.into());
self
}
}
impl TerraformCommand for ShowCommand {
type Output = ShowResult;
fn args(&self) -> Vec<String> {
let mut args = vec!["show".to_string()];
if self.json {
args.push("-json".to_string());
}
args.extend(self.raw_args.clone());
if let Some(ref plan) = self.plan_file {
args.push(plan.clone());
}
args
}
async fn execute(&self, tf: &Terraform) -> Result<ShowResult> {
let output = exec::run_terraform(tf, self.args()).await?;
if !self.json {
return Ok(ShowResult::Plain(output));
}
#[cfg(feature = "json")]
if self.plan_file.is_some() {
let plan: crate::types::plan::PlanRepresentation = serde_json::from_str(&output.stdout)
.map_err(|e| crate::error::Error::Json {
message: "failed to parse plan json".to_string(),
source: e,
})?;
return Ok(ShowResult::Plan(Box::new(plan)));
}
#[cfg(feature = "json")]
{
let state: crate::types::state::StateRepresentation =
serde_json::from_str(&output.stdout).map_err(|e| crate::error::Error::Json {
message: "failed to parse state json".to_string(),
source: e,
})?;
Ok(ShowResult::State(state))
}
#[cfg(not(feature = "json"))]
Ok(ShowResult::Plain(output))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_args_include_json() {
let cmd = ShowCommand::new();
assert_eq!(cmd.args(), vec!["show", "-json"]);
}
#[test]
fn plan_file_at_end() {
let cmd = ShowCommand::new().plan_file("tfplan");
assert_eq!(cmd.args(), vec!["show", "-json", "tfplan"]);
}
#[test]
fn no_json_args() {
let cmd = ShowCommand::new().no_json();
assert_eq!(cmd.args(), vec!["show"]);
}
#[test]
fn no_json_with_plan_file() {
let cmd = ShowCommand::new().no_json().plan_file("tfplan");
assert_eq!(cmd.args(), vec!["show", "tfplan"]);
}
}