1use steps::{Step, Context, error::StepError};
13use config::steps::StepConfig;
14use cmd::*;
15use display::*;
16
17pub struct RawCmdStep { name: String, raw_cmd: String }
24
25impl Step for RawCmdStep {
26
27 fn execute (&self, context: &Context) -> Result<(), StepError> {
28
29 let server_command = format!("cd {} && {}", context.release_path.trim(), self.raw_cmd);
30 let status = exec_remote_cmd_inherit_output(&context.config.host, &server_command)?;
31
32 if !status.success() {
33 return Err(StepError::from_failed_command(&self.raw_cmd, status.code()));
34 }
35
36 Ok(())
37 }
38
39 fn get_name(&self) -> &str {
40 &self.name
41 }
42}
43
44impl From<StepConfig> for RawCmdStep {
45 fn from(config_step: StepConfig) -> Self {
46 RawCmdStep { name: config_step.name, raw_cmd: config_step.comand}
47 }
48}
49
50pub struct InitStep;
53
54impl Step for InitStep {
55
56 fn execute (&self, context: &Context) -> Result<(), StepError> {
57 let create_release_path_cmd = format!("mkdir -p {}", context.release_path);
58
59 let status = exec_remote_cmd(&context.config.host, &create_release_path_cmd)?.status;
60
61 if !status.success() {
62 return Err(StepError::from_failed_command(&create_release_path_cmd, status.code()));
63 }
64
65 Ok(())
66 }
67
68 fn get_name(&self) -> &str {
69 "core:init"
70 }
71}
72
73pub struct LinkFiles;
74
75impl Step for LinkFiles {
76
77 fn execute (&self, context: &Context) -> Result<(), StepError> {
78
79 for file in context.config.link_files.iter() {
80 let shared_file_path = format!("{}/{}", context.shared_path, file);
81 let symlink_path = format!("{}/{}", context.release_path.trim(), file);
82
83 let file_exists = exec_remote_file_exists(&context.config.host, &shared_file_path, FSResourceType::File)?;
84
85 if !file_exists {
86 let error_msg = format!("Could not create symlink for file {} because it doesn't exist", file);
87 return Err(StepError::Critical(error_msg));
88 }
89
90 let symlink_command = format!("ln -s {} {}",shared_file_path, symlink_path);
91
92 let status = exec_remote_cmd(&context.config.host, &symlink_command)?.status;
93
94 if !status.success() {
95 return Err(StepError::from_failed_command(&symlink_command, status.code()));
96 }
97 }
98
99 Ok(())
100 }
101
102 fn get_name(&self) -> &str {
103 "core:link:files"
104 }
105}
106
107pub struct LinkDirs;
108
109impl Step for LinkDirs {
110
111 fn execute (&self, context: &Context) -> Result<(), StepError> {
112
113 for dir in context.config.link_dirs.iter() {
114 let shared_dir_path = format!("{}/{}", context.shared_path, dir);
115 let symlink_path = format!("{}/{}", context.release_path.trim(), dir);
116
117 let dir_exists = exec_remote_file_exists(&context.config.host, &shared_dir_path, FSResourceType::Directory)?;
118
119 if !dir_exists {
120 let error_msg = format!("Could not create symlink for dir {} because it doesn't exist", dir);
121 return Err(StepError::Critical(error_msg));
122 }
123
124 let symlink_command = format!("ln -s {} {}", shared_dir_path, symlink_path);
125 let status = exec_remote_cmd(&context.config.host, &symlink_command)?.status;
126
127 if !status.success() {
128 return Err(StepError::from_failed_command(&symlink_command, status.code()));
129 }
130 }
131
132 Ok(())
133 }
134
135 fn get_name(&self) -> &str {
136 "core:link:directories"
137 }
138}
139
140pub struct SymlinkCurrent;
141
142impl Step for SymlinkCurrent {
143
144 fn execute (&self, context: &Context) -> Result<(), StepError> {
145
146 let current_symlink_path = format!("{}/current", context.config.deploy_path);
147
148 let current_symlink_exist = exec_remote_file_exists(&context.config.host, ¤t_symlink_path, FSResourceType::Symlink)?;
149
150 if current_symlink_exist {
151 let remove_current_command = format!("rm {}", current_symlink_path);
152
153 let status = exec_remote_cmd(&context.config.host, &remove_current_command)?.status;
154
155 if !status.success() {
156 return Err(StepError::from_failed_command(&remove_current_command, status.code()));
157 }
158 }
159
160 let create_current_symlink_cmd = format!("ln -s {} {}", context.release_path.trim(), current_symlink_path);
161
162 let status = exec_remote_cmd(&context.config.host, &create_current_symlink_cmd)?.status;
163
164 if !status.success() {
165 return Err(StepError::from_failed_command(&create_current_symlink_cmd, status.code()));
166 }
167
168 Ok(())
169 }
170
171 fn get_name(&self) -> &str {
172 "core:link:current"
173 }
174}
175
176pub struct CleanUpReleases;
177
178impl Step for CleanUpReleases {
179
180 fn execute (&self, context: &Context) -> Result<(), StepError> {
181
182 let mut releases = exec_remote_fetch_sorted_filenames_in_dir(&context.config.host, &context.releases_path, SortOrder::Asc)
183 .map_err(|e| StepError::non_critical_from_error(e))?;
184
185 let keep_releases = context.config.keep_releases as usize;
186 let total_releases = releases.len();
187
188 if total_releases <= keep_releases { return Ok(()); };
189 let to_remove = total_releases - keep_releases;
190 releases.resize(to_remove, "".into());
191
192 for release_dir in &releases {
193 let delete_dir_cmd = format!("rm -rf {}/{}", &context.releases_path, release_dir);
194 let output = exec_remote_cmd(&context.config.host, &delete_dir_cmd)?;
195
196 if !output.status.success() {
197 render_error(&format!("Failed to clean up old release {}", release_dir));
198 }
199
200 println!("Deleted: {}", release_dir);
201 }
202
203 Ok(())
204 }
205
206
207 fn get_name(&self) -> &str {
208 "core:cleanup:releases"
209 }
210}