Improve error handling
+ Alias for returning Result with varying Error types + Update all Result returns to use new alias + Documentation comments for functions and structs + Add move_dir and move_file functions to fs wrapper module + Add `--force` flag for overwriting an existing configuration backup
This commit is contained in:
		
							parent
							
								
									fded317a65
								
							
						
					
					
						commit
						069f5cc128
					
				
							
								
								
									
										72
									
								
								src/kot.rs
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								src/kot.rs
									
									
									
									
									
								
							| @ -13,20 +13,24 @@ pub mod cli; | |||||||
| pub mod fs; | pub mod fs; | ||||||
| pub mod io; | pub mod io; | ||||||
| 
 | 
 | ||||||
|  | /// Result alias to return result with Error of various types
 | ||||||
|  | pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>; | ||||||
|  | 
 | ||||||
| // =============================================================================
 | // =============================================================================
 | ||||||
| // IMPLEMENTATION
 | // IMPLEMENTATION
 | ||||||
| // =============================================================================
 | // =============================================================================
 | ||||||
| 
 | 
 | ||||||
| // -----------------------------------------------------------------------------
 | // -----------------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| // Creates symbolic links to the configurations we're installing
 | /// Creates symbolic links to the configurations we're installing
 | ||||||
| // TODO: On error, revert to last good state
 | // TODO: On error, revert to last good state
 | ||||||
| // TODO: User script to execute after installing configs successfully
 | // TODO: User script to execute after installing configs successfully
 | ||||||
| // TODO: Function to uninstall configs. Loop through dotfiles and restore backup files or delete configs
 | pub fn install_configs(args: & cli::Cli) -> Result<()> { | ||||||
| pub fn install_configs(args: & cli::Cli) -> std::io::Result<()> { |  | ||||||
|     // Get the configurations and their target installation paths
 |     // Get the configurations and their target installation paths
 | ||||||
|     // + Checks for conflicts and prompts user to abort or continue
 |     // + Checks for conflicts and prompts user to abort or continue
 | ||||||
|     let config_map = fs::get_target_paths(&args)?; |     let config_map = fs::get_target_paths(&args)?; | ||||||
|  | 
 | ||||||
|  |     // Check if there are any existing files in the install directory that are also within the dotfiles to install
 | ||||||
|     handle_collisions(&args, &config_map)?; |     handle_collisions(&args, &config_map)?; | ||||||
| 
 | 
 | ||||||
|     // At this point there are either no conflicts or the user agreed to them
 |     // At this point there are either no conflicts or the user agreed to them
 | ||||||
| @ -36,7 +40,7 @@ pub fn install_configs(args: & cli::Cli) -> std::io::Result<()> { | |||||||
|         match std::os::unix::fs::symlink(config_path, target_path) { |         match std::os::unix::fs::symlink(config_path, target_path) { | ||||||
|             Ok(()) => (), // Configuration installed successfully
 |             Ok(()) => (), // Configuration installed successfully
 | ||||||
|             Err(_e) => { |             Err(_e) => { | ||||||
|                 // Attempt to remove the file or directory, and then symlink the new config
 |                 // Attempt to remove the file or directory first, and then symlink the new config
 | ||||||
|                 match target_path.is_dir() { |                 match target_path.is_dir() { | ||||||
|                     true => fs_extra::dir::remove(target_path) |                     true => fs_extra::dir::remove(target_path) | ||||||
|                         .expect(&format!("Error: Unable to remove directory: {:?}", target_path)), |                         .expect(&format!("Error: Unable to remove directory: {:?}", target_path)), | ||||||
| @ -44,21 +48,23 @@ pub fn install_configs(args: & cli::Cli) -> std::io::Result<()> { | |||||||
|                         .expect(&format!("Error: Unable to remove file: {:?}", target_path)), |                         .expect(&format!("Error: Unable to remove file: {:?}", target_path)), | ||||||
|                 }; |                 }; | ||||||
|                 // Try to symlink the config again, if failure exit with error
 |                 // Try to symlink the config again, if failure exit with error
 | ||||||
|                 std::os::unix::fs::symlink(config_path, target_path) |                 std::os::unix::fs::symlink(config_path, target_path)?; | ||||||
|                     .expect(&format!("Unable to symlink config: {:?}", config_path)); |  | ||||||
|             }, |             }, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Handles collisions between existing files and dotfiles we're installing
 | ||||||
| fn handle_collisions(args : & cli::Cli, | fn handle_collisions(args : & cli::Cli, | ||||||
|                      config_map : & fs::HashMap<PathBuf, PathBuf>) -> io::Result<()> { |                      config_map : & fs::HashMap<PathBuf, PathBuf>) -> Result<()> { | ||||||
|     let conflicts = check_collisions(&config_map) |     // Check if we found any collisions in the configurations
 | ||||||
|         .expect("Error: Failed to check collisions"); |     match check_collisions(&config_map) { | ||||||
| 
 |         None => { | ||||||
|     // If we found collisions in the configurations
 |             return Ok(()) // There were no collisions, configurations pass pre-install checks
 | ||||||
|     if &conflicts.len() > &0 { |         }, | ||||||
|  |         Some(conflicts) => { | ||||||
|             // Ask client if they would like to abort given the config collisions
 |             // Ask client if they would like to abort given the config collisions
 | ||||||
|             let mut msg = format!("The following configurations already exist:"); |             let mut msg = format!("The following configurations already exist:"); | ||||||
|             for config in conflicts.iter() { |             for config in conflicts.iter() { | ||||||
| @ -69,44 +75,58 @@ fn handle_collisions(args : & cli::Cli, | |||||||
|                             \nAbort? Enter y/n or Y/N: ", &args.backup_dir).as_str();
 |                             \nAbort? Enter y/n or Y/N: ", &args.backup_dir).as_str();
 | ||||||
| 
 | 
 | ||||||
|             // If we abort, exit; If we continue, back up the configs
 |             // If we abort, exit; If we continue, back up the configs
 | ||||||
|  |             // TODO: Group this in with the --force flag?; Or make a new --adopt flag?
 | ||||||
|             match io::prompt(msg) { |             match io::prompt(msg) { | ||||||
|             true => return Err(std::io::Error::from(std::io::ErrorKind::AlreadyExists)), |                 true => return Ok(()), | ||||||
|                 false => { |                 false => { | ||||||
|                     // Backup each conflicting config at the install location
 |                     // Backup each conflicting config at the install location
 | ||||||
|                     for backup_target in conflicts.iter() { |                     for backup_target in conflicts.iter() { | ||||||
|                     backup_config(backup_target, &args.backup_dir) |                         backup_config(backup_target, &args)?; | ||||||
|                         .expect(format!("Error: Unable to backup config: {:?}", backup_target) |  | ||||||
|                             .as_str()) |  | ||||||
|                     } |                     } | ||||||
|                 }, |                 }, | ||||||
|             }; |             }; | ||||||
|  | 
 | ||||||
|  |         }, | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Creates a backup of configurations that conflict
 | // Creates a backup of configurations that conflict
 | ||||||
| // + Backup directory location is specified by CLI --backup-dir
 | // + Backup directory location is specified by CLI --backup-dir
 | ||||||
| // TODO: Automatically create backup directory
 |  | ||||||
| // TODO: .kotignore in dotfiles repo to specify files to not install / backup
 | // TODO: .kotignore in dotfiles repo to specify files to not install / backup
 | ||||||
| // TODO: .kotrc in dotfiles repo or home dir to set backup-dir and install-dir?
 | // TODO: .kotrc in dotfiles repo or home dir to set backup-dir and install-dir?
 | ||||||
| fn backup_config(config_path: & fs::PathBuf, backup_dir: & fs::PathBuf) -> io::Result<()> { | fn backup_config(config_path: & fs::PathBuf, args: & cli::Cli) -> Result<()> { | ||||||
|     let mut backup_path = backup_dir.to_owned(); |     let mut backup_path = args.backup_dir.to_owned(); | ||||||
|     backup_path.push(config_path.file_name().unwrap()); |     backup_path.push(config_path.file_name().unwrap()); | ||||||
|  | 
 | ||||||
|  |     // Check if the configuration we're backing up is a directory or a single file
 | ||||||
|     match config_path.is_dir() { |     match config_path.is_dir() { | ||||||
|         true => { |         true => { | ||||||
|             // Copy directory with recursion using fs_extra::dir::move_dir
 |             // Copy directory with recursion using move_dir() wrapper function
 | ||||||
|             let mut options = fs::dir::CopyOptions::new(); |             let mut options = fs::dir::CopyOptions::new(); | ||||||
|             options.copy_inside = true; |             options.copy_inside = true; | ||||||
|             // TODO: Add a flag to overwrite backups, otherwise warn and abort
 |             options.overwrite = args.force; | ||||||
|             options.overwrite = true; |             if let Err(e) = fs::move_dir(config_path, &backup_path, Some(&options)) | ||||||
|             fs::dir::move_dir(config_path, backup_path, &options) |                 .map_err(|e| e.into()) { | ||||||
|  |                 return Err(e) | ||||||
|  |             } | ||||||
|         }, |         }, | ||||||
|         false => { |         false => { | ||||||
|             // Copy single configuration file
 |             // Copy single configuration file
 | ||||||
|             let mut options = fs_extra::file::CopyOptions::new(); |             let mut options = fs_extra::file::CopyOptions::new(); | ||||||
|             options.overwrite = true; |             options.overwrite = args.force; | ||||||
|             fs_extra::file::move_file(config_path, backup_path, &options) |             if let Err(e) = fs::move_file(config_path, &backup_path, Some(&options)) | ||||||
|  |                 .map_err(|e| e.into()) { | ||||||
|  |                 return Err(e) | ||||||
|  |             } | ||||||
|         }, |         }, | ||||||
|     }.expect(&format!("Error: Unable to backup config: {:?}", config_path)); |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TODO: Function to uninstall configs.
 | ||||||
|  | // + Loops through dotfiles and restore backup files or delete configs
 | ||||||
|  | fn _uninstall_configs() -> Result<()> { | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ | |||||||
| ## Contact: shaunrd0@gmail.com  | URL: www.shaunreed.com | GitHub: shaunrd0   ## | ## Contact: shaunrd0@gmail.com  | URL: www.shaunreed.com | GitHub: shaunrd0   ## | ||||||
| ##############################################################################*/ | ##############################################################################*/ | ||||||
| 
 | 
 | ||||||
|  | use std::path::Path; | ||||||
| use structopt::StructOpt; | use structopt::StructOpt; | ||||||
| 
 | 
 | ||||||
| // =============================================================================
 | // =============================================================================
 | ||||||
| @ -14,6 +15,7 @@ use structopt::StructOpt; | |||||||
| 
 | 
 | ||||||
| // -----------------------------------------------------------------------------
 | // -----------------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
|  | /// Struct to outline behavior and features of kot CLI
 | ||||||
| #[derive(Debug, StructOpt)] | #[derive(Debug, StructOpt)] | ||||||
| #[structopt(
 | #[structopt(
 | ||||||
|     name="kot", |     name="kot", | ||||||
| @ -44,6 +46,12 @@ pub struct Cli { | |||||||
|         parse(from_os_str) |         parse(from_os_str) | ||||||
|     )] |     )] | ||||||
|     pub backup_dir: std::path::PathBuf, |     pub backup_dir: std::path::PathBuf, | ||||||
|  | 
 | ||||||
|  |     #[structopt(
 | ||||||
|  |         help="Overwrites existing backups", | ||||||
|  |         short, long | ||||||
|  |     )] | ||||||
|  |     pub force: bool, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // =============================================================================
 | // =============================================================================
 | ||||||
| @ -52,28 +60,54 @@ pub struct Cli { | |||||||
| 
 | 
 | ||||||
| // -----------------------------------------------------------------------------
 | // -----------------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| // Augment implementation of from_args to limit scope of StructOpt
 | /// Augment implementation of from_args to limit scope of StructOpt
 | ||||||
| // + Also enforces use of Cli::normalize()
 | /// + Also enforces use of Cli::normalize()
 | ||||||
| // https://docs.rs/structopt/0.3.23/src/structopt/lib.rs.html#1121-1126
 | /// + https://docs.rs/structopt/0.3.23/src/structopt/lib.rs.html#1121-1126
 | ||||||
| pub fn from_args() -> Cli { | pub fn from_args() -> super::Result<Cli> { | ||||||
|     let s = Cli::from_clap(&Cli::clap().get_matches()); |     let s = Cli::from_clap(&Cli::clap().get_matches()); | ||||||
|     s.normalize() |     s.normalize() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Cli { | impl Cli { | ||||||
|     // Helper function to normalize arguments passed to program
 |     /// Helper function to normalize arguments passed to program
 | ||||||
|     pub fn normalize(mut self) -> Self { |     pub fn normalize(mut self) -> super::Result<Self> { | ||||||
|         // If the path to the dotfiles doesn't exist, exit with error
 |         // If the path to the dotfiles doesn't exist, exit with error
 | ||||||
|         if !&self.dotfiles_dir.exists() { |         if !&self.dotfiles_dir.exists() { | ||||||
|             panic!("Error: Dotfiles configuration at {:?} does not exist", self.dotfiles_dir); |             panic!("Error: Dotfiles configuration at {:?} does not exist", self.dotfiles_dir); | ||||||
|         } |         } | ||||||
|         self.dotfiles_dir = self.dotfiles_dir.canonicalize().unwrap(); |         self.dotfiles_dir = self.dotfiles_dir.canonicalize()?; | ||||||
| 
 | 
 | ||||||
|         // If either the install or backup dir don't exist, create them
 |         // If either the install or backup dir don't exist, create them
 | ||||||
|         std::fs::create_dir_all(&self.install_dir).ok(); |         std::fs::create_dir_all(&self.install_dir)?; | ||||||
|         self.install_dir = self.install_dir.canonicalize().unwrap(); |         self.install_dir = self.install_dir.canonicalize()?; | ||||||
|         std::fs::create_dir_all(&self.backup_dir).ok(); |         std::fs::create_dir_all(&self.backup_dir)?; | ||||||
|         self.backup_dir = self.backup_dir.canonicalize().unwrap(); |         self.backup_dir = self.backup_dir.canonicalize()?; | ||||||
|         self | 
 | ||||||
|  |         // + To enforce the correction when error is encountered
 | ||||||
|  |         // Get the number of configs currently in backup directory
 | ||||||
|  |         // + An empty backup directory returns a count of 1
 | ||||||
|  |         let current_backups = self.backup_dir.read_dir()?.count(); | ||||||
|  |         // If there are files in the backup directory already
 | ||||||
|  |         if current_backups > 1 { | ||||||
|  |             // If the --force flag is not set, warn and abort
 | ||||||
|  |             if !self.force { | ||||||
|  |                 panic!("\n  Error: Backups already exist at {:?}\ | ||||||
|  |                 \n  Set the --force flag to overwrite configurations stored here" , self.backup_dir)
 | ||||||
|  |             } | ||||||
|  |             // If the --force flag is set, remove backups and create new
 | ||||||
|  |             // + Move backups to /tmp/<BACKUP_DIRNAME>
 | ||||||
|  |             // + If we encounter an error, we can move these temp files back to args.backup_dir
 | ||||||
|  |             // + On success we can delete them since new backups will have been created at args.backup_dir
 | ||||||
|  |             let mut options = fs_extra::dir::CopyOptions::new(); | ||||||
|  |             options.copy_inside = true; | ||||||
|  |             options.overwrite = true; | ||||||
|  |             let mut temp_path = Path::new("/tmp/").to_path_buf(); | ||||||
|  |             temp_path.push(self.backup_dir.file_name().unwrap()); | ||||||
|  |             // Move the old backups to /tmp/ and create a new empty backup directory
 | ||||||
|  |             super::fs::move_dir( &self.backup_dir, &temp_path, Some(&options))?; | ||||||
|  |             std::fs::create_dir_all(&self.backup_dir)?; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Ok(self) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -19,39 +19,36 @@ use std::fs; | |||||||
| 
 | 
 | ||||||
| // -----------------------------------------------------------------------------
 | // -----------------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| // Initialize and return a HashMap<config_dir, config_install_location>
 | /// Initialize and return a HashMap<config_dir, config_install_location>
 | ||||||
| // Later used to check each install location for conflicts before installing
 | /// + Later used to check each install location for conflicts before installing
 | ||||||
| // This function does not create or modify any files or directories
 | /// + This function does not create or modify any files or directories
 | ||||||
| pub fn get_target_paths(args: & super::cli::Cli) -> super::io::Result<HashMap<PathBuf, PathBuf>> { | pub fn get_target_paths(args: & super::cli::Cli) -> super::Result<HashMap<PathBuf, PathBuf>> { | ||||||
|     let mut config_map = HashMap::new(); |     let mut config_map = HashMap::new(); | ||||||
| 
 | 
 | ||||||
|     // Local variable for the installation directory as an absolute path
 |     // Local variable for the installation directory as an absolute path
 | ||||||
|     let mut config_target = args.install_dir.to_owned(); |     let mut config_target = args.install_dir.to_owned(); | ||||||
|     // For each file or directory within the dotfiles we're installing
 |     // For each file or directory within the dotfiles we're installing
 | ||||||
|     for config_entry in fs::read_dir(&args.dotfiles_dir)? { |     for config_entry in fs::read_dir(&args.dotfiles_dir)? { | ||||||
|         // Match result from reading each item in dotfiles, return error if any
 |         let entry = config_entry?; | ||||||
|         match config_entry { |  | ||||||
|             Err(err) => return Err(err), |  | ||||||
|             Ok(entry) => { |  | ||||||
|         // Create full path to target config file (or directory) by push onto install path
 |         // Create full path to target config file (or directory) by push onto install path
 | ||||||
|         config_target.push(entry.file_name()); |         config_target.push(entry.file_name()); | ||||||
| 
 | 
 | ||||||
|         // If the entry doesn't already exist, insert it into the config_map
 |         // If the entry doesn't already exist, insert it into the config_map
 | ||||||
|                 // Key is full path to source config from dotfiles repo we're installing
 |         // + Key is full path to source config from dotfiles repo we're installing
 | ||||||
|                 // Value is desired full path to config at final install location
 |         // + Value is desired full path to config at final install location
 | ||||||
|         // TODO: If the entry does exist, should there be an exception?
 |         // TODO: If the entry does exist, should there be an exception?
 | ||||||
|         config_map.entry(entry.path().to_owned()) |         config_map.entry(entry.path().to_owned()) | ||||||
|             .or_insert(config_target.to_owned()); |             .or_insert(config_target.to_owned()); | ||||||
| 
 | 
 | ||||||
|         // Reset config_target to be equal to requested install_dir
 |         // Reset config_target to be equal to requested install_dir
 | ||||||
|         config_target.pop(); |         config_target.pop(); | ||||||
|             }, |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     Ok(config_map) |     Ok(config_map) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn check_collisions(config_map : & HashMap<PathBuf, PathBuf>) -> super::io::Result<Vec<PathBuf>> { | /// Checks if any config to install collides with existing files or directories
 | ||||||
|  | /// + Returns a count of collisions within Some(), else returns None
 | ||||||
|  | pub fn check_collisions(config_map : & HashMap<PathBuf, PathBuf>) -> Option<Vec<PathBuf>> { | ||||||
|     let mut config_conflicts = vec![]; |     let mut config_conflicts = vec![]; | ||||||
|     for (_path, target_config) in config_map.iter() { |     for (_path, target_config) in config_map.iter() { | ||||||
|         // If the target configuration file or directory already exists
 |         // If the target configuration file or directory already exists
 | ||||||
| @ -59,6 +56,35 @@ pub fn check_collisions(config_map : & HashMap<PathBuf, PathBuf>) -> super::io:: | |||||||
|             config_conflicts.push(target_config.to_owned()); |             config_conflicts.push(target_config.to_owned()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     Ok(config_conflicts) |     if config_conflicts.len() > 0 { | ||||||
|  |         return Some(config_conflicts) | ||||||
|  |     } | ||||||
|  |     return None | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Moves a single file from one location to another; Can be used to rename files
 | ||||||
|  | /// + To specify options such as overwrite for the copy operation, a custom CopyOptions can be provided
 | ||||||
|  | pub fn move_file(src: & PathBuf, dst: & PathBuf, | ||||||
|  |                 options: Option< & fs_extra::file::CopyOptions>) -> super::Result<()> { | ||||||
|  |     if options.is_none() { | ||||||
|  |         // Default CopyOptions for moving files
 | ||||||
|  |         let mut options = fs_extra::file::CopyOptions::new(); | ||||||
|  |         options.overwrite = false; | ||||||
|  |     } | ||||||
|  |     fs_extra::file::move_file(src, dst, options.unwrap())?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Moves a directory and all of it's contents recursively
 | ||||||
|  | /// + To specify options such as overwrite for the copy operation, a custom CopyOptions can be provided
 | ||||||
|  | pub fn move_dir(src: & PathBuf, dst: & PathBuf, | ||||||
|  |                 options: Option< & fs_extra::dir::CopyOptions>) -> super::Result<()> { | ||||||
|  |     if options.is_none() { | ||||||
|  |         // Default CopyOptions for moving directories
 | ||||||
|  |         let mut options = fs_extra::dir::CopyOptions::new(); | ||||||
|  |         options.copy_inside = true; | ||||||
|  |         options.overwrite = false; | ||||||
|  |     } | ||||||
|  |     fs_extra::dir::move_dir(src, dst, options.unwrap())?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | |||||||
| @ -17,8 +17,8 @@ use std::io; | |||||||
| 
 | 
 | ||||||
| // -----------------------------------------------------------------------------
 | // -----------------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| // Asks user for y/n Y/N input, returns true/false respectively
 | /// Asks user for y/n Y/N input, returns true/false respectively
 | ||||||
| // + Prompt output defined by msg parameter String
 | /// + Prompt output defined by msg parameter String
 | ||||||
| pub fn prompt(msg: String) -> bool { | pub fn prompt(msg: String) -> bool { | ||||||
|     println!("{}", msg); |     println!("{}", msg); | ||||||
|     let mut reply = String::new(); |     let mut reply = String::new(); | ||||||
|  | |||||||
							
								
								
									
										25
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -6,6 +6,8 @@ | |||||||
| ## Contact: shaunrd0@gmail.com  | URL: www.shaunreed.com | GitHub: shaunrd0   ## | ## Contact: shaunrd0@gmail.com  | URL: www.shaunreed.com | GitHub: shaunrd0   ## | ||||||
| ##############################################################################*/ | ##############################################################################*/ | ||||||
| 
 | 
 | ||||||
|  | use std::path::PathBuf; | ||||||
|  | 
 | ||||||
| mod kot; | mod kot; | ||||||
| 
 | 
 | ||||||
| // =============================================================================
 | // =============================================================================
 | ||||||
| @ -14,9 +16,9 @@ mod kot; | |||||||
| 
 | 
 | ||||||
| // -----------------------------------------------------------------------------
 | // -----------------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| fn main() { | fn main() -> kot::Result<()> { | ||||||
|     // Call augmented kot::cli::from_args() to parse CLI arguments
 |     // Call augmented kot::cli::from_args() to parse CLI arguments
 | ||||||
|     let args = kot::cli::from_args(); |     let args = kot::cli::from_args()?; | ||||||
|     // At this point all paths exist and have been converted to absolute paths
 |     // At this point all paths exist and have been converted to absolute paths
 | ||||||
|     println!("args: {:?}\n", args); |     println!("args: {:?}\n", args); | ||||||
| 
 | 
 | ||||||
| @ -26,10 +28,19 @@ fn main() { | |||||||
|             // If there was an error, show the error type and run settings
 |             // If there was an error, show the error type and run settings
 | ||||||
|             println!( |             println!( | ||||||
|                 "Error: {:?}\n+ Configs used: {:?}\n+ Install directory: {:?}\n", |                 "Error: {:?}\n+ Configs used: {:?}\n+ Install directory: {:?}\n", | ||||||
|                 e.kind(), args.dotfiles_dir, args.install_dir |                 e, args.dotfiles_dir, args.install_dir | ||||||
|             ) |             ); | ||||||
|         }, | 
 | ||||||
|         // Configurations installed successfully
 |             // If we were forcing a backup and met some error, revert backups to last good state
 | ||||||
|         Ok(()) => (), |             // TODO: Isolate this to limit error scope to backup related functions
 | ||||||
|  |             if args.force { | ||||||
|  |                 let mut temp_path : PathBuf = kot::fs::Path::new("/tmp/").to_path_buf(); | ||||||
|  |                 temp_path.push(args.backup_dir.file_name().unwrap()); | ||||||
|  |                 kot::fs::move_dir(&temp_path, &args.backup_dir, None)?; | ||||||
|             } |             } | ||||||
|  |         }, | ||||||
|  |         _ => () | ||||||
|  |     } | ||||||
|  |     // Configurations installed successfully
 | ||||||
|  |     Ok(()) | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user