terraform_wrapper/commands/
init.rs1use crate::Terraform;
2use crate::command::TerraformCommand;
3use crate::error::Result;
4use crate::exec::{self, CommandOutput};
5
6#[derive(Debug, Clone, Default)]
22pub struct InitCommand {
23 backend_configs: Vec<(String, String)>,
24 backend_config_files: Vec<String>,
25 upgrade: bool,
26 reconfigure: bool,
27 migrate_state: bool,
28 plugin_dir: Option<String>,
29 lock: Option<bool>,
30 lock_timeout: Option<String>,
31 raw_args: Vec<String>,
32}
33
34impl InitCommand {
35 #[must_use]
37 pub fn new() -> Self {
38 Self::default()
39 }
40
41 #[must_use]
43 pub fn backend_config(mut self, key: &str, value: &str) -> Self {
44 self.backend_configs
45 .push((key.to_string(), value.to_string()));
46 self
47 }
48
49 #[must_use]
51 pub fn backend_config_file(mut self, path: &str) -> Self {
52 self.backend_config_files.push(path.to_string());
53 self
54 }
55
56 #[must_use]
58 pub fn upgrade(mut self) -> Self {
59 self.upgrade = true;
60 self
61 }
62
63 #[must_use]
65 pub fn reconfigure(mut self) -> Self {
66 self.reconfigure = true;
67 self
68 }
69
70 #[must_use]
72 pub fn migrate_state(mut self) -> Self {
73 self.migrate_state = true;
74 self
75 }
76
77 #[must_use]
79 pub fn plugin_dir(mut self, path: &str) -> Self {
80 self.plugin_dir = Some(path.to_string());
81 self
82 }
83
84 #[must_use]
86 pub fn lock(mut self, enabled: bool) -> Self {
87 self.lock = Some(enabled);
88 self
89 }
90
91 #[must_use]
93 pub fn lock_timeout(mut self, timeout: &str) -> Self {
94 self.lock_timeout = Some(timeout.to_string());
95 self
96 }
97
98 #[must_use]
100 pub fn arg(mut self, arg: impl Into<String>) -> Self {
101 self.raw_args.push(arg.into());
102 self
103 }
104}
105
106impl TerraformCommand for InitCommand {
107 type Output = CommandOutput;
108
109 fn args(&self) -> Vec<String> {
110 let mut args = vec!["init".to_string()];
111
112 for (key, value) in &self.backend_configs {
113 args.push(format!("-backend-config={key}={value}"));
114 }
115 for file in &self.backend_config_files {
116 args.push(format!("-backend-config={file}"));
117 }
118 if self.upgrade {
119 args.push("-upgrade".to_string());
120 }
121 if self.reconfigure {
122 args.push("-reconfigure".to_string());
123 }
124 if self.migrate_state {
125 args.push("-migrate-state".to_string());
126 }
127 if let Some(ref dir) = self.plugin_dir {
128 args.push(format!("-plugin-dir={dir}"));
129 }
130 if let Some(lock) = self.lock {
131 args.push(format!("-lock={lock}"));
132 }
133 if let Some(ref timeout) = self.lock_timeout {
134 args.push(format!("-lock-timeout={timeout}"));
135 }
136 args.extend(self.raw_args.clone());
137 args
138 }
139
140 async fn execute(&self, tf: &Terraform) -> Result<CommandOutput> {
141 let mut args = self.args();
142 if tf.no_input {
143 args.insert(1, "-input=false".to_string());
144 }
145 exec::run_terraform(tf, args).await
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[test]
154 fn default_args() {
155 let cmd = InitCommand::new();
156 assert_eq!(cmd.args(), vec!["init"]);
157 }
158
159 #[test]
160 fn all_options() {
161 let cmd = InitCommand::new()
162 .backend_config("key", "value")
163 .backend_config_file("backend.hcl")
164 .upgrade()
165 .reconfigure()
166 .plugin_dir("/plugins")
167 .lock(false)
168 .lock_timeout("10s");
169 let args = cmd.args();
170 assert!(args.contains(&"-backend-config=key=value".to_string()));
171 assert!(args.contains(&"-backend-config=backend.hcl".to_string()));
172 assert!(args.contains(&"-upgrade".to_string()));
173 assert!(args.contains(&"-reconfigure".to_string()));
174 assert!(args.contains(&"-plugin-dir=/plugins".to_string()));
175 assert!(args.contains(&"-lock=false".to_string()));
176 assert!(args.contains(&"-lock-timeout=10s".to_string()));
177 }
178
179 #[test]
180 fn raw_arg_escape_hatch() {
181 let cmd = InitCommand::new().arg("-from-module=./staging");
182 let args = cmd.args();
183 assert!(args.contains(&"-from-module=./staging".to_string()));
184 }
185}