From a32b1001c3f28870c39346a97ad2f2d82dbf2479 Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Tue, 25 Sep 2018 23:25:28 +0100 Subject: [PATCH] Stylistic changes from cargo fmt and cargo clippy. --- src/cmd.rs | 33 +++++++---- src/config/stages/error.rs | 10 +++- src/config/stages/mod.rs | 60 ++++++++++--------- src/config/steps/error.rs | 2 +- src/config/steps/mod.rs | 80 ++++++++++++++++--------- src/lib.rs | 22 ++++--- src/main.rs | 16 +++-- src/recipe/deployer.rs | 62 ++++++++++--------- src/recipe/mod.rs | 88 ++++++++++++++++++--------- src/steps/core.rs | 118 ++++++++++++++++++++++++------------- src/steps/error.rs | 13 ++-- src/steps/git.rs | 10 ++-- src/steps/mod.rs | 61 ++++++++++++++----- src/steps/rollback.rs | 52 +++++++++------- 14 files changed, 393 insertions(+), 234 deletions(-) diff --git a/src/cmd.rs b/src/cmd.rs index 895f398..905fa75 100755 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -3,15 +3,17 @@ //! These functions are mostly used by deployment steps to perform //! the different actions they need to do while deployment or rolling back. -use std::process::{Command, Stdio, Output, ExitStatus}; use std::io; +use std::process::{Command, ExitStatus, Output, Stdio}; +#[derive(Copy, Clone)] pub enum FSResourceType { File, Directory, - Symlink + Symlink, } +#[derive(Copy, Clone)] pub enum SortOrder { Asc, Des, @@ -19,7 +21,6 @@ pub enum SortOrder { /// Executes a command on the server and returns its output or an IO error. pub fn exec_remote_cmd(host: &str, cmd: &str) -> Result { - let output = Command::new("ssh").args(&[host, cmd]).output()?; Ok(output) @@ -28,7 +29,6 @@ pub fn exec_remote_cmd(host: &str, cmd: &str) -> Result { /// Executes a command on the server and pipes its output directly to stdout. /// It returns the command `ExitStatus` or an IO error. pub fn exec_remote_cmd_inherit_output(host: &str, cmd: &str) -> Result { - let mut child = Command::new("ssh") .args(&[host, cmd]) .stdout(Stdio::inherit()) @@ -41,12 +41,15 @@ pub fn exec_remote_cmd_inherit_output(host: &str, cmd: &str) -> Result Result { - +pub fn exec_remote_file_exists( + host: &str, + file_path: &str, + resource_type: FSResourceType, +) -> Result { let type_key = match resource_type { FSResourceType::File => "f", FSResourceType::Directory => "d", - FSResourceType::Symlink => "L" + FSResourceType::Symlink => "L", }; let cmd = format!("test -{} {}", type_key, file_path); @@ -57,18 +60,24 @@ pub fn exec_remote_file_exists(host: &str, file_path: &str, resource_type: FSRes /// Given a path, it returns a vector containing the filenames of all the files inside that path /// sorted in descending order. -pub fn exec_remote_fetch_sorted_filenames_in_dir(host: &str, dir_path: &str, sort_order: SortOrder) -> Result, io::Error> { - +pub fn exec_remote_fetch_sorted_filenames_in_dir( + host: &str, + dir_path: &str, + sort_order: SortOrder, +) -> Result, io::Error> { let sort_cmd = match sort_order { SortOrder::Asc => "sort", - SortOrder::Des => "sort -r" + SortOrder::Des => "sort -r", }; - let cmd = format!("find {} -maxdepth 1 -mindepth 1 -printf '%f\n' | {}", dir_path, sort_cmd); + let cmd = format!( + "find {} -maxdepth 1 -mindepth 1 -printf '%f\n' | {}", + dir_path, sort_cmd + ); let output = exec_remote_cmd(host, &cmd)?; let stdout = String::from_utf8_lossy(&output.stdout); - let vector: Vec = stdout.trim_right().split("\n").map(|x| String::from(x)).collect(); + let vector: Vec = stdout.trim_right().split('\n').map(String::from).collect(); Ok(vector) } diff --git a/src/config/stages/error.rs b/src/config/stages/error.rs index ba7ab60..b80f6c8 100755 --- a/src/config/stages/error.rs +++ b/src/config/stages/error.rs @@ -12,7 +12,7 @@ pub enum ConfigError { BadType(String, String), ///Parameters: (field_name) MissingField(String), - IoError + IoError, } impl fmt::Display for ConfigError { @@ -22,8 +22,12 @@ impl fmt::Display for ConfigError { BadStage(ref env) => write!(f, "Couldn't find stage '{}' in config file", env), BadType(ref name, ref expected) => { write!(f, "type mismatch for '{}'. expected {}", name, expected) - }, - MissingField(ref name) => write!(f, "Required field '{}' is missing from the config file", name), + } + MissingField(ref name) => write!( + f, + "Required field '{}' is missing from the config file", + name + ), IoError => write!(f, "I/O error while reading the config file"), } } diff --git a/src/config/stages/mod.rs b/src/config/stages/mod.rs index c0d0c09..93ec597 100755 --- a/src/config/stages/mod.rs +++ b/src/config/stages/mod.rs @@ -1,7 +1,7 @@ +use std::collections::HashMap; use std::fs::File; use std::io::prelude::*; use toml_edit::*; -use std::collections::HashMap; pub mod error; @@ -14,15 +14,15 @@ pub struct HostConfig { pub keep_releases: i8, pub repo_url: String, pub link_files: Vec, - pub link_dirs: Vec + pub link_dirs: Vec, } pub fn parse_config_file(file_name: &str, stage: &str) -> Result { - let mut file = File::open(file_name) - .map_err(|_| ConfigError::NotFound(stage.into()))?; + let mut file = File::open(file_name).map_err(|_| ConfigError::NotFound(stage.into()))?; let mut contents = String::new(); - file.read_to_string(&mut contents).map_err(|_| ConfigError::IoError)?; + file.read_to_string(&mut contents) + .map_err(|_| ConfigError::IoError)?; let doc = contents.parse::().unwrap(); @@ -31,9 +31,7 @@ pub fn parse_config_file(file_name: &str, stage: &str) -> Result table, - None => { - return Err(ConfigError::BadStage(stage.into())) - } + None => return Err(ConfigError::BadStage(stage.into())), }; let mut config_map = HashMap::new(); @@ -41,35 +39,33 @@ pub fn parse_config_file(file_name: &str, stage: &str) -> Result) -> Result { let value = match hash_map.get(key) { Some(value) => match value.as_integer() { Some(value) => value, - None => return Err(ConfigError::BadType(key.into(), "integer".into())) + None => return Err(ConfigError::BadType(key.into(), "integer".into())), }, - None => return Err(ConfigError::MissingField(key.into())) + None => return Err(ConfigError::MissingField(key.into())), }; Ok(value) @@ -79,21 +75,27 @@ fn parse_string(key: &str, hash_map: &HashMap<&str, &Item>) -> Result match value.as_str() { Some(value) => value, - None => return Err(ConfigError::BadType(key.into(), "string".into())) + None => return Err(ConfigError::BadType(key.into(), "string".into())), }, - None => return Err(ConfigError::MissingField(key.into())) + None => return Err(ConfigError::MissingField(key.into())), }; Ok(value.into()) } -fn parse_string_vector(key: &str, hash_map: &HashMap<&str, &Item>) -> Result, ConfigError> { +fn parse_string_vector( + key: &str, + hash_map: &HashMap<&str, &Item>, +) -> Result, ConfigError> { let value = match hash_map.get(key) { Some(value) => match value.as_array() { - Some(value) => value.iter().map(|value| value.as_str().unwrap().to_string()).collect(), - None => return Err(ConfigError::BadType(key.into(), "array".into())) + Some(value) => value + .iter() + .map(|value| value.as_str().unwrap().to_string()) + .collect(), + None => return Err(ConfigError::BadType(key.into(), "array".into())), }, - None => return Err(ConfigError::MissingField(key.into())) + None => return Err(ConfigError::MissingField(key.into())), }; Ok(value) diff --git a/src/config/steps/error.rs b/src/config/steps/error.rs index 099e736..348452e 100644 --- a/src/config/steps/error.rs +++ b/src/config/steps/error.rs @@ -12,7 +12,7 @@ pub enum StepConfigError { AmbiguousPosition, //The position field is missing from the configuration. MissingPosition, - IoError + IoError, } impl fmt::Display for StepConfigError { diff --git a/src/config/steps/mod.rs b/src/config/steps/mod.rs index 418c881..e2c13d1 100644 --- a/src/config/steps/mod.rs +++ b/src/config/steps/mod.rs @@ -1,15 +1,15 @@ pub mod error; -use std::io::{ErrorKind, Read}; -use std::fs::File; use self::error::{StepConfigError, StepConfigError::*}; -use toml_edit::*; use std::collections::HashMap; +use std::fs::File; +use std::io::{ErrorKind, Read}; +use toml_edit::*; #[derive(Debug, Clone)] pub enum StepPosition { Before, - After + After, } #[derive(Debug, Clone)] @@ -17,25 +17,29 @@ pub struct StepConfig { pub name: String, pub comand: String, pub position: StepPosition, - pub ref_step: String + pub ref_step: String, } type Steps = HashMap; -pub fn parse_steps_config_file(file_name: &str, stage: &str) -> Result, StepConfigError> { +pub fn parse_steps_config_file( + file_name: &str, + stage: &str, +) -> Result, StepConfigError> { let file = File::open(file_name); //return empty vector if steps file is not present. if file.is_err() { match file.unwrap_err().kind() { ErrorKind::NotFound => return Ok(Vec::new()), - _ => return Err(StepConfigError::IoError) + _ => return Err(StepConfigError::IoError), } } let mut file = file.unwrap(); let mut contents = String::new(); - file.read_to_string(&mut contents).map_err(|_| StepConfigError::IoError)?; + file.read_to_string(&mut contents) + .map_err(|_| StepConfigError::IoError)?; let doc = contents.parse::().unwrap(); @@ -43,50 +47,68 @@ pub fn parse_steps_config_file(file_name: &str, stage: &str) -> Result = steps_map.drain().map(|(_, k)| { k }).collect(); + let steps_collection: Vec = steps_map.drain().map(|(_, k)| k).collect(); Ok(steps_collection) } -fn parse_steps_and_add_to_hashmap(doc: &Document, stage: &str, collection: &mut Steps) - -> Result<(), StepConfigError> { - +fn parse_steps_and_add_to_hashmap( + doc: &Document, + stage: &str, + collection: &mut Steps, +) -> Result<(), StepConfigError> { if let Some(stage_steps) = doc[stage]["steps"].as_array_of_tables() { for table in stage_steps.iter() { let step = parse_step_table(table)?; collection.insert(step.name.to_owned(), step); - }; + } } Ok(()) } fn parse_step_table(table: &Table) -> Result { - let name = table.get("name").ok_or(MissingField("name".into()))?.as_str() - .ok_or(BadType("name".into(), "string".into()))?.to_string(); - - let comand = table.get("command").ok_or(MissingField("command".into()))?.as_str() - .ok_or(BadType("command".into(), "string".into()))?.to_string(); + let name = table + .get("name") + .ok_or_else(|| MissingField("name".into()))? + .as_str() + .ok_or_else(|| BadType("name".into(), "string".into()))? + .to_string(); + + let comand = table + .get("command") + .ok_or_else(|| MissingField("command".into()))? + .as_str() + .ok_or_else(|| BadType("command".into(), "string".into()))? + .to_string(); if !table.contains_key("before") && !table.contains_key("after") { - return Err(AmbiguousPosition) + return Err(AmbiguousPosition); }; let (position, ref_step) = if table.contains_key("before") { - let ref_step = table.get("before").unwrap().as_str().ok_or(BadType("before".into(), "string".into()))?.to_string(); + let ref_step = table + .get("before") + .unwrap() + .as_str() + .ok_or_else(|| BadType("before".into(), "string".into()))? + .to_string(); (StepPosition::Before, ref_step) } else if table.contains_key("after") { - let ref_step = table.get("after").unwrap().as_str().ok_or(BadType("after".into(), "string".into()))?.to_string(); + let ref_step = table + .get("after") + .unwrap() + .as_str() + .ok_or_else(|| BadType("after".into(), "string".into()))? + .to_string(); (StepPosition::After, ref_step) } else { return Err(MissingPosition); }; - Ok( - StepConfig { - name, - comand, - position, - ref_step - } - ) + Ok(StepConfig { + name, + comand, + position, + ref_step, + }) } diff --git a/src/lib.rs b/src/lib.rs index e5eaca7..6b5727f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,26 +1,26 @@ -extern crate toml_edit; extern crate ansi_term; +extern crate toml_edit; -pub mod recipe; -pub mod steps; +mod cmd; pub mod config; mod display; -mod cmd; +pub mod recipe; +pub mod steps; use config::stages::parse_config_file; use config::steps::{parse_steps_config_file, StepConfig}; +use std::error::Error; use std::process::exit; use steps::Context; -use std::error::Error; +#[derive(Clone, Copy)] pub enum Operation { Deploy, - Rollback + Rollback, } pub fn init_stage_context(config_file: &str, stage: &str, opt: Operation) -> Context { - - let host_config = match parse_config_file(config_file, stage) { + let host_config = match parse_config_file(config_file, stage) { Ok(context) => context, Err(config_error) => { eprintln!("config error: {}", config_error); @@ -28,15 +28,13 @@ pub fn init_stage_context(config_file: &str, stage: &str, opt: Operation) -> Con } }; - let context = match Context::from_host_config(host_config, opt) { + match Context::from_host_config(host_config, opt) { Ok(context) => context, Err(message) => { eprintln!("error: {:?}", message.description()); exit(1); } - }; - - context + } } pub fn init_steps_from_config(config_file: &str, stage: &str) -> Vec { diff --git a/src/main.rs b/src/main.rs index de192c1..799b317 100755 --- a/src/main.rs +++ b/src/main.rs @@ -3,10 +3,10 @@ extern crate trappo; extern crate serde_derive; extern crate docopt; -use trappo::recipe::{Recipe, deployer::*}; use docopt::Docopt; +use trappo::recipe::{deployer::*, Recipe}; -const USAGE: &'static str = " +const USAGE: &str = " trappo Usage: @@ -28,11 +28,17 @@ struct Args { } fn main() { - let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize()).unwrap_or_else(|e| e.exit()); - let opt = if args.cmd_deploy { trappo::Operation::Deploy } else { trappo::Operation::Rollback }; + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + let opt = if args.cmd_deploy { + trappo::Operation::Deploy + } else { + trappo::Operation::Rollback + }; let stage_context = trappo::init_stage_context(".trappo/config.toml", &args.arg_stage, opt); - let config_steps = trappo::init_steps_from_config(".trappo/steps.toml", &args.arg_stage); + let config_steps = trappo::init_steps_from_config(".trappo/steps.toml", &args.arg_stage); let recipe = Recipe::build() .name("Main Recipe") diff --git a/src/recipe/deployer.rs b/src/recipe/deployer.rs index 62514a1..f6e64b7 100644 --- a/src/recipe/deployer.rs +++ b/src/recipe/deployer.rs @@ -1,45 +1,51 @@ -use steps::{Context, Step, error::StepError}; -use display::*; use super::Recipe; +use display::*; +use steps::{error::StepError, Context, Step}; pub fn deploy(recipe: &Recipe, context: &Context) -> Result<(), ()> { - - render_success(&format!("🚀 Deploying to {} using '{}' recipe...", context.config.host, recipe.name)); - - execute_steps(&recipe.steps, &context) - .or_else(|err_msg| { - render_error(&format!("💣 Critical error : {}", err_msg)); - rollback(&recipe, &context) - } - ) + render_success(&format!( + "🚀 Deploying to {} using '{}' recipe...", + context.config.host, recipe.name + )); + + execute_steps(&recipe.steps, &context).or_else(|err_msg| { + render_error(&format!("💣 Critical error : {}", err_msg)); + rollback(&recipe, &context) + }) } pub fn rollback(recipe: &Recipe, context: &Context) -> Result<(), ()> { - - render_success(&format!("🤦‍ Rolling back on {} using '{}' recipe...", context.config.host, recipe.name)); - - execute_steps(&recipe.rollback_steps, &context) - .or_else(|err_msg| { - render_error(&format!("💣 Could not roll back because of critical error : {}", err_msg)); - Err(()) - } - ) + render_success(&format!( + "🤦‍ Rolling back on {} using '{}' recipe...", + context.config.host, recipe.name + )); + + execute_steps(&recipe.rollback_steps, &context).or_else(|err_msg| { + render_error(&format!( + "💣 Could not roll back because of critical error : {}", + err_msg + )); + Err(()) + }) } -fn execute_steps(steps: &Vec>, context: &Context) -> Result<(), String> { +fn execute_steps(steps: &[Box], context: &Context) -> Result<(), String> { for step in steps.iter() { render_success(&format!("➜ Executing step {}...", step.get_name())); match step.execute(context) { - Ok(_) => render_success(&format!("🗸 Step {} executed successfully", step.get_name())), - Err(step_error) => { - match step_error { - StepError::Critical(msg) => return Err(msg), - StepError::NonCritical(_) => render_error(&format!("Non-critical error, continuing")) + Ok(_) => render_success(&format!( + "🗸 Step {} executed successfully", + step.get_name() + )), + Err(step_error) => match step_error { + StepError::Critical(msg) => return Err(msg), + StepError::NonCritical(_) => { + render_error(&"Non-critical error, continuing".to_string()) } - } + }, }; - }; + } Ok(()) } diff --git a/src/recipe/mod.rs b/src/recipe/mod.rs index c12c624..d3828ea 100755 --- a/src/recipe/mod.rs +++ b/src/recipe/mod.rs @@ -1,33 +1,30 @@ pub mod deployer; -use steps::{Step, core::*, git::*, rollback::*}; use config::steps::{StepConfig, StepPosition::*}; use std::cell::RefCell; +use steps::{core::*, git::*, rollback::*, Step}; pub struct Recipe { - pub name : String, + pub name: String, pub steps: Vec>, - pub rollback_steps: Vec> + pub rollback_steps: Vec>, } impl Recipe { - pub fn build() -> RecipeBuilder { RecipeBuilder { - recipe: Some(RefCell::new(Recipe::default())) + recipe: Some(RefCell::new(Recipe::default())), } } fn get_step_index(&self, step_name: &str) -> Option { let mut node_index: Option = None; - let mut index: usize = 0; - for step in &self.steps { + for (index, step) in self.steps.iter().enumerate() { if step.get_name() == step_name { node_index = Some(index); break; } - index += 1; } node_index @@ -39,13 +36,13 @@ impl Default for Recipe { Recipe { name: "Anonymous Recipe".into(), steps: Vec::new(), - rollback_steps: Vec::new() + rollback_steps: Vec::new(), } } } pub struct RecipeBuilder { - recipe: Option> + recipe: Option>, } impl RecipeBuilder { @@ -80,8 +77,12 @@ impl RecipeBuilder { if let Some(ref mut recipe) = self.recipe { let mut recipe_ref = recipe.borrow_mut(); recipe_ref.rollback_steps.push(Box::new(CanRollBack)); - recipe_ref.rollback_steps.push(Box::new(RemoveCurrentRelease)); - recipe_ref.rollback_steps.push(Box::new(SymlinkPreviousRelease)); + recipe_ref + .rollback_steps + .push(Box::new(RemoveCurrentRelease)); + recipe_ref + .rollback_steps + .push(Box::new(SymlinkPreviousRelease)); } self @@ -92,15 +93,26 @@ impl RecipeBuilder { /// ///panics if reference steps are not found in the inner vector pub fn with_config_steps(&mut self, config_steps: Vec) -> &mut Self { - if let Some(ref mut recipe) = self.recipe { for step_config in config_steps.into_iter() { - let mut step_index = recipe.borrow().get_step_index(&step_config.ref_step) - .expect(&format!("Step '{}' doesn't exist in the recipe", &step_config.ref_step)); - - if let After = step_config.position { step_index += 1 }; - recipe.borrow_mut().steps.insert(step_index, Box::new(RawCmdStep::from(step_config))); - }; + let mut step_index = recipe + .borrow() + .get_step_index(&step_config.ref_step) + .unwrap_or_else(|| { + panic!( + "Step '{}' doesn't exist in the recipe", + &step_config.ref_step + ) + }); + + if let After = step_config.position { + step_index += 1 + }; + recipe + .borrow_mut() + .steps + .insert(step_index, Box::new(RawCmdStep::from(step_config))); + } } self } @@ -108,12 +120,21 @@ impl RecipeBuilder { ///Add step after another /// ///panics if step is not found in the inner vector - pub fn with_step_after(&mut self, subject_name: &str, extra_step: T) -> &mut Self { + pub fn with_step_after( + &mut self, + subject_name: &str, + extra_step: T, + ) -> &mut Self { if let Some(ref mut recipe) = self.recipe { - let step_index = recipe.borrow().get_step_index(subject_name) - .expect(&format!("Step '{}' doesn't exist in the recipe", subject_name)); - - recipe.borrow_mut().steps.insert(step_index + 1, Box::new(extra_step)); + let step_index = recipe + .borrow() + .get_step_index(subject_name) + .unwrap_or_else(|| panic!("Step '{}' doesn't exist in the recipe", subject_name)); + + recipe + .borrow_mut() + .steps + .insert(step_index + 1, Box::new(extra_step)); } self @@ -122,12 +143,21 @@ impl RecipeBuilder { ///Add step before another /// ///panics if step is not found in the inner vector - pub fn with_step_before(&mut self, subject_name: &str, extra_step: T) -> &mut Self { + pub fn with_step_before( + &mut self, + subject_name: &str, + extra_step: T, + ) -> &mut Self { if let Some(ref mut recipe) = self.recipe { - let step_index = recipe.borrow().get_step_index(subject_name) - .expect(&format!("Step '{}' doesn't exist in the recipe", subject_name)); - - recipe.borrow_mut().steps.insert(step_index, Box::new(extra_step)); + let step_index = recipe + .borrow() + .get_step_index(subject_name) + .unwrap_or_else(|| panic!("Step '{}' doesn't exist in the recipe", subject_name)); + + recipe + .borrow_mut() + .steps + .insert(step_index, Box::new(extra_step)); } self diff --git a/src/steps/core.rs b/src/steps/core.rs index bd74e52..9d505ab 100755 --- a/src/steps/core.rs +++ b/src/steps/core.rs @@ -9,10 +9,10 @@ //! `.trappo/steps.toml` file end up being. And they can be executed during deployment by invoking the //! recipe builder's `.with_steps_from_file(file_name: String)` method. <- TODO implementation. -use steps::{Step, Context, error::StepError}; -use config::steps::StepConfig; use cmd::*; +use config::steps::StepConfig; use display::*; +use steps::{error::StepError, Context, Step}; /// This struct is what commands feed to the program using an external /// `.trappo/steps.toml` file end up being. And they can be executed during deployment by invoking the @@ -20,12 +20,13 @@ use display::*; /// /// It executes the command provided in the config file directly on the server, if the command fails /// it returns a critial error which will trigger a rollback. The output of the command is shown in the terminal. -pub struct RawCmdStep { name: String, raw_cmd: String } +pub struct RawCmdStep { + name: String, + raw_cmd: String, +} impl Step for RawCmdStep { - - fn execute (&self, context: &Context) -> Result<(), StepError> { - + fn execute(&self, context: &Context) -> Result<(), StepError> { let server_command = format!("cd {} && {}", context.release_path.trim(), self.raw_cmd); let status = exec_remote_cmd_inherit_output(&context.config.host, &server_command)?; @@ -43,7 +44,10 @@ impl Step for RawCmdStep { impl From for RawCmdStep { fn from(config_step: StepConfig) -> Self { - RawCmdStep { name: config_step.name, raw_cmd: config_step.comand} + RawCmdStep { + name: config_step.name, + raw_cmd: config_step.comand, + } } } @@ -52,14 +56,16 @@ impl From for RawCmdStep { pub struct InitStep; impl Step for InitStep { - - fn execute (&self, context: &Context) -> Result<(), StepError> { + fn execute(&self, context: &Context) -> Result<(), StepError> { let create_release_path_cmd = format!("mkdir -p {}", context.release_path); let status = exec_remote_cmd(&context.config.host, &create_release_path_cmd)?.status; if !status.success() { - return Err(StepError::from_failed_command(&create_release_path_cmd, status.code())); + return Err(StepError::from_failed_command( + &create_release_path_cmd, + status.code(), + )); } Ok(()) @@ -73,26 +79,34 @@ impl Step for InitStep { pub struct LinkFiles; impl Step for LinkFiles { - - fn execute (&self, context: &Context) -> Result<(), StepError> { - + fn execute(&self, context: &Context) -> Result<(), StepError> { for file in context.config.link_files.iter() { let shared_file_path = format!("{}/{}", context.shared_path, file); - let symlink_path = format!("{}/{}", context.release_path.trim(), file); + let symlink_path = format!("{}/{}", context.release_path.trim(), file); - let file_exists = exec_remote_file_exists(&context.config.host, &shared_file_path, FSResourceType::File)?; + let file_exists = exec_remote_file_exists( + &context.config.host, + &shared_file_path, + FSResourceType::File, + )?; if !file_exists { - let error_msg = format!("Could not create symlink for file {} because it doesn't exist", file); + let error_msg = format!( + "Could not create symlink for file {} because it doesn't exist", + file + ); return Err(StepError::Critical(error_msg)); } - let symlink_command = format!("ln -s {} {}",shared_file_path, symlink_path); + let symlink_command = format!("ln -s {} {}", shared_file_path, symlink_path); let status = exec_remote_cmd(&context.config.host, &symlink_command)?.status; if !status.success() { - return Err(StepError::from_failed_command(&symlink_command, status.code())); + return Err(StepError::from_failed_command( + &symlink_command, + status.code(), + )); } } @@ -107,17 +121,22 @@ impl Step for LinkFiles { pub struct LinkDirs; impl Step for LinkDirs { - - fn execute (&self, context: &Context) -> Result<(), StepError> { - + fn execute(&self, context: &Context) -> Result<(), StepError> { for dir in context.config.link_dirs.iter() { let shared_dir_path = format!("{}/{}", context.shared_path, dir); - let symlink_path = format!("{}/{}", context.release_path.trim(), dir); + let symlink_path = format!("{}/{}", context.release_path.trim(), dir); - let dir_exists = exec_remote_file_exists(&context.config.host, &shared_dir_path, FSResourceType::Directory)?; + let dir_exists = exec_remote_file_exists( + &context.config.host, + &shared_dir_path, + FSResourceType::Directory, + )?; if !dir_exists { - let error_msg = format!("Could not create symlink for dir {} because it doesn't exist", dir); + let error_msg = format!( + "Could not create symlink for dir {} because it doesn't exist", + dir + ); return Err(StepError::Critical(error_msg)); } @@ -125,7 +144,10 @@ impl Step for LinkDirs { let status = exec_remote_cmd(&context.config.host, &symlink_command)?.status; if !status.success() { - return Err(StepError::from_failed_command(&symlink_command, status.code())); + return Err(StepError::from_failed_command( + &symlink_command, + status.code(), + )); } } @@ -140,12 +162,14 @@ impl Step for LinkDirs { pub struct SymlinkCurrent; impl Step for SymlinkCurrent { - - fn execute (&self, context: &Context) -> Result<(), StepError> { - + fn execute(&self, context: &Context) -> Result<(), StepError> { let current_symlink_path = format!("{}/current", context.config.deploy_path); - let current_symlink_exist = exec_remote_file_exists(&context.config.host, ¤t_symlink_path, FSResourceType::Symlink)?; + let current_symlink_exist = exec_remote_file_exists( + &context.config.host, + ¤t_symlink_path, + FSResourceType::Symlink, + )?; if current_symlink_exist { let remove_current_command = format!("rm {}", current_symlink_path); @@ -153,16 +177,26 @@ impl Step for SymlinkCurrent { let status = exec_remote_cmd(&context.config.host, &remove_current_command)?.status; if !status.success() { - return Err(StepError::from_failed_command(&remove_current_command, status.code())); + return Err(StepError::from_failed_command( + &remove_current_command, + status.code(), + )); } } - let create_current_symlink_cmd = format!("ln -s {} {}", context.release_path.trim(), current_symlink_path); + let create_current_symlink_cmd = format!( + "ln -s {} {}", + context.release_path.trim(), + current_symlink_path + ); let status = exec_remote_cmd(&context.config.host, &create_current_symlink_cmd)?.status; if !status.success() { - return Err(StepError::from_failed_command(&create_current_symlink_cmd, status.code())); + return Err(StepError::from_failed_command( + &create_current_symlink_cmd, + status.code(), + )); } Ok(()) @@ -176,16 +210,19 @@ impl Step for SymlinkCurrent { pub struct CleanUpReleases; impl Step for CleanUpReleases { - - fn execute (&self, context: &Context) -> Result<(), StepError> { - - let mut releases = exec_remote_fetch_sorted_filenames_in_dir(&context.config.host, &context.releases_path, SortOrder::Asc) - .map_err(|e| StepError::non_critical_from_error(e))?; - - let keep_releases = context.config.keep_releases as usize; + fn execute(&self, context: &Context) -> Result<(), StepError> { + let mut releases = exec_remote_fetch_sorted_filenames_in_dir( + &context.config.host, + &context.releases_path, + SortOrder::Asc, + ).map_err(|e| StepError::non_critical_from_error(&e))?; + + let keep_releases = context.config.keep_releases as usize; let total_releases = releases.len(); - if total_releases <= keep_releases { return Ok(()); }; + if total_releases <= keep_releases { + return Ok(()); + }; let to_remove = total_releases - keep_releases; releases.resize(to_remove, "".into()); @@ -203,7 +240,6 @@ impl Step for CleanUpReleases { Ok(()) } - fn get_name(&self) -> &str { "core:cleanup:releases" } diff --git a/src/steps/error.rs b/src/steps/error.rs index 630b774..0f3b92e 100644 --- a/src/steps/error.rs +++ b/src/steps/error.rs @@ -1,25 +1,28 @@ -use std::io; use std::error::Error; +use std::io; #[derive(Debug)] pub enum StepError { ///Critical error Critical(String), ///Non-critical error - NonCritical(String) + NonCritical(String), } impl StepError { pub fn from_failed_command(cmd: &str, status: Option) -> Self { let error_msg = match status { - Some(code) => format!("Command '{}' exited with non-sucessful status code '{}'", cmd, code), - None => format!("Command '{}' exited with non-sucessful status code", cmd) + Some(code) => format!( + "Command '{}' exited with non-sucessful status code '{}'", + cmd, code + ), + None => format!("Command '{}' exited with non-sucessful status code", cmd), }; StepError::Critical(error_msg) } - pub fn non_critical_from_error(error: E) -> Self { + pub fn non_critical_from_error(error: &E) -> Self { StepError::NonCritical(error.to_string()) } } diff --git a/src/steps/git.rs b/src/steps/git.rs index 1480cad..6f73674 100755 --- a/src/steps/git.rs +++ b/src/steps/git.rs @@ -1,11 +1,10 @@ -use steps::{Step, Context, error::StepError}; use cmd::*; +use steps::{error::StepError, Context, Step}; pub struct GitClone; impl Step for GitClone { - - fn execute (&self, context: &Context) -> Result<(), StepError> { + fn execute(&self, context: &Context) -> Result<(), StepError> { let server_command = format!( "git clone {} {}", context.config.repo_url.trim(), @@ -15,7 +14,10 @@ impl Step for GitClone { let status = exec_remote_cmd_inherit_output(&context.config.host, &server_command)?; if !status.success() { - return Err(StepError::from_failed_command(&server_command, status.code())); + return Err(StepError::from_failed_command( + &server_command, + status.code(), + )); } Ok(()) diff --git a/src/steps/mod.rs b/src/steps/mod.rs index 7dcc8e8..5f5e6c7 100644 --- a/src/steps/mod.rs +++ b/src/steps/mod.rs @@ -1,13 +1,13 @@ -use config::stages::HostConfig; -use std::io::{Error, ErrorKind}; use self::error::StepError; -use super::Operation; use super::cmd::*; +use super::Operation; +use config::stages::HostConfig; +use std::io::{Error, ErrorKind}; pub mod core; -pub mod rollback; -pub mod git; pub mod error; +pub mod git; +pub mod rollback; #[derive(Debug)] pub struct Context { @@ -29,45 +29,74 @@ impl Context { fn rollback_context(config: HostConfig) -> Result { let shared_path = format!("{}/shared", config.deploy_path); let releases_path = format!("{}/releases", config.deploy_path); - let existing_releases = exec_remote_fetch_sorted_filenames_in_dir(&config.host, &releases_path, SortOrder::Des)?; + let existing_releases = exec_remote_fetch_sorted_filenames_in_dir( + &config.host, + &releases_path, + SortOrder::Des, + )?; //get the current release currently on the server. - let release_path = existing_releases.get(0) + let release_path = existing_releases + .get(0) .map(|name| format!("{}/{}", releases_path, name)); let release_path = if let Some(path) = release_path { path } else { - return Err(Error::new(ErrorKind::Other, "There are no releases on the server")); + return Err(Error::new( + ErrorKind::Other, + "There are no releases on the server", + )); }; //get the previous release (target for rollback). - let prev_release_path = existing_releases.get(1) + let prev_release_path = existing_releases + .get(1) .map(|name| format!("{}/{}", releases_path, name)); - Ok(Context { config, releases_path, release_path, prev_release_path, shared_path }) + Ok(Context { + config, + releases_path, + release_path, + prev_release_path, + shared_path, + }) } fn deploy_context(config: HostConfig) -> Result { let output = exec_remote_cmd(&config.host, "date +'%Y%m%d%H%M%S'")?; if !output.status.success() { - return Err(Error::new(ErrorKind::Other, "Failed to compute current timestamp at the server")) + return Err(Error::new( + ErrorKind::Other, + "Failed to compute current timestamp at the server", + )); } let releases_path = format!("{}/releases", config.deploy_path); - let existing_releases = exec_remote_fetch_sorted_filenames_in_dir(&config.host, &releases_path, SortOrder::Des)?; + let existing_releases = exec_remote_fetch_sorted_filenames_in_dir( + &config.host, + &releases_path, + SortOrder::Des, + )?; //get the newest release currently on the server (used in case of rollback). - let prev_release_path = existing_releases.get(0) + let prev_release_path = existing_releases + .get(0) .map(|name| format!("{}/{}", releases_path, name)); let release_timestamp = String::from_utf8_lossy(&output.stdout); let releases_path = format!("{}/releases", config.deploy_path); - let release_path = format!("{}/{}", releases_path, release_timestamp); - let shared_path = format!("{}/shared", config.deploy_path); + let release_path = format!("{}/{}", releases_path, release_timestamp); + let shared_path = format!("{}/shared", config.deploy_path); - Ok(Context { config, releases_path, release_path, prev_release_path, shared_path }) + Ok(Context { + config, + releases_path, + release_path, + prev_release_path, + shared_path, + }) } } diff --git a/src/steps/rollback.rs b/src/steps/rollback.rs index 06b7fc7..38e3d9f 100644 --- a/src/steps/rollback.rs +++ b/src/steps/rollback.rs @@ -1,6 +1,6 @@ //! Contains the default steps performed during a rollback. -use steps::{Step, Context, error::StepError}; use cmd::*; +use steps::{error::StepError, Context, Step}; const NO_PREV_ERR_MSG: &str = "Can't rollback because there is no release to rollback to."; @@ -10,9 +10,12 @@ pub struct CanRollBack; /// Checks whether or not there is a release to rollback to. If the `Context.prev_release_path` /// contains a `None`, then the rollback is not possible. impl Step for CanRollBack { - - fn execute (&self, context: &Context) -> Result<(), StepError> { - context.prev_release_path.as_ref().ok_or(StepError::Critical(NO_PREV_ERR_MSG.into())).map(|_| ()) + fn execute(&self, context: &Context) -> Result<(), StepError> { + context + .prev_release_path + .as_ref() + .ok_or_else(|| StepError::Critical(NO_PREV_ERR_MSG.into())) + .map(|_| ()) } fn get_name(&self) -> &str { @@ -27,19 +30,16 @@ pub struct RemoveCurrentRelease; /// Removes all the files from the relase we are rolling back from. impl Step for RemoveCurrentRelease { - - fn execute (&self, context: &Context) -> Result<(), StepError> { - + fn execute(&self, context: &Context) -> Result<(), StepError> { let release_path = &context.release_path; let cmd = format!("rm -rf {}", release_path); let output = exec_remote_cmd(&context.config.host, &cmd)?; - match output.status.success() { - true => Ok(()), - false => { - let err_msg = format!("Failed to remove current release at {}", release_path); - Err(StepError::Critical(err_msg)) - } + if output.status.success() { + Ok(()) + } else { + let err_msg = format!("Failed to remove current release at {}", release_path); + Err(StepError::Critical(err_msg)) } } @@ -52,11 +52,13 @@ impl Step for RemoveCurrentRelease { pub struct SymlinkPreviousRelease; impl Step for SymlinkPreviousRelease { - - fn execute (&self, context: &Context) -> Result<(), StepError> { - + fn execute(&self, context: &Context) -> Result<(), StepError> { let current_symlink_path = format!("{}/current", context.config.deploy_path); - let current_symlink_exist = exec_remote_file_exists(&context.config.host, ¤t_symlink_path, FSResourceType::Symlink)?; + let current_symlink_exist = exec_remote_file_exists( + &context.config.host, + ¤t_symlink_path, + FSResourceType::Symlink, + )?; //remove current symlink if it exists. if current_symlink_exist { @@ -65,16 +67,26 @@ impl Step for SymlinkPreviousRelease { let status = exec_remote_cmd(&context.config.host, &remove_current_command)?.status; if !status.success() { - return Err(StepError::from_failed_command(&remove_current_command, status.code())); + return Err(StepError::from_failed_command( + &remove_current_command, + status.code(), + )); } } let prev_release_path = context.prev_release_path.as_ref().unwrap(); - let create_current_symlink_cmd = format!("ln -s {} {}", prev_release_path.trim(), current_symlink_path); + let create_current_symlink_cmd = format!( + "ln -s {} {}", + prev_release_path.trim(), + current_symlink_path + ); let status = exec_remote_cmd(&context.config.host, &create_current_symlink_cmd)?.status; if !status.success() { - return Err(StepError::from_failed_command(&create_current_symlink_cmd, status.code())); + return Err(StepError::from_failed_command( + &create_current_symlink_cmd, + status.code(), + )); } Ok(())