From 1097180010be89077645ffef5d71000af36b49d3 Mon Sep 17 00:00:00 2001 From: "Artem Zinnatullin :slowpoke" Date: Wed, 14 Nov 2018 22:00:26 -0800 Subject: [PATCH] Replicate local absolute path on remote machine (#236) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #214. As discussed in #214, we now replicate absolute path from local machine in `~/mainframer/…` on remote machine. This allows user to have multiple projects with same leaf node in the path without clashing, ie: - `/home/artem_zin/myproject` → `/home/remote_user/mainframer/home/artem_zin/myproject` - `/home/artem_zin/projects/myproject` → `/home/remote_user/mainframer/home/artem_zin/projects/myproject` We can also add local machine hostname, but I don't think it's a good idea. --- Integration tests were updated to expect files in new path. Also tested myself. --- src/main.rs | 30 +++++++++++++++--------------- src/sync.rs | 15 ++++++++------- test/common.sh | 2 +- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/main.rs b/src/main.rs index aa6d2ec..f1fc235 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,8 @@ use args::Args; use config::Config; use ignore::*; use std::env; +use std::fs; +use std::path::Path; use std::process; use std::time::Instant; use time::*; @@ -22,14 +24,12 @@ fn main() { Ok(value) => value, }; - let working_dir = match env::current_dir() { + let local_dir_absolute_path = match env::current_dir() { Err(_) => exit_with_error(&"Could not resolve working directory, make sure it exists and user has enough permissions to work with it.", 1), - Ok(value) => value + Ok(value) => fs::canonicalize(value).unwrap() }; - let working_dir_name = working_dir.file_name().unwrap().to_string_lossy().clone(); - - let mut config_file = working_dir.clone(); + let mut config_file = local_dir_absolute_path.to_owned(); config_file.push(".mainframer/config"); let config = match Config::from_file(config_file.as_path()) { @@ -37,17 +37,17 @@ fn main() { Ok(value) => value }; - let ignore = Ignore::from_working_dir(&working_dir); + let ignore = Ignore::from_working_dir(&local_dir_absolute_path); let start = Instant::now(); - if let Err(error) = sync_before_remote_command(&working_dir_name, &config, &ignore) { + if let Err(error) = sync_before_remote_command(&local_dir_absolute_path, &config, &ignore) { exit_with_error(&format!("Sync local → remote machine failed: {}.", error), 1) } - let remote_command_result = execute_remote_command(&working_dir_name, &args, &config); + let remote_command_result = execute_remote_command(&local_dir_absolute_path, &args, &config); - if let Err(error) = sync_after_remote_command(&working_dir_name, &config, &ignore) { + if let Err(error) = sync_after_remote_command(&local_dir_absolute_path, &config, &ignore) { exit_with_error(&format!("Sync remote → local machine failed: {}.", error), 1) } @@ -66,13 +66,13 @@ fn exit_with_error(message: &str, code: i32) -> ! { process::exit(code); } -fn sync_before_remote_command(working_dir_name: &str, config: &Config, ignore: &Ignore) -> Result<(), String> { +fn sync_before_remote_command(local_dir_absolute_path: &Path, config: &Config, ignore: &Ignore) -> Result<(), String> { println!("Sync local → remote machine..."); let start = Instant::now(); let result = sync::sync_local_to_remote( - &working_dir_name, + &local_dir_absolute_path, config, ignore, ); @@ -88,7 +88,7 @@ fn sync_before_remote_command(working_dir_name: &str, config: &Config, ignore: & } } -fn execute_remote_command(working_dir_name: &str, args: &Args, config: &Config) -> Result<(), ()> { +fn execute_remote_command(local_dir_absolute_path: &Path, args: &Args, config: &Config) -> Result<(), ()> { println!("Executing command on remote machine...\n"); let start = Instant::now(); @@ -96,7 +96,7 @@ fn execute_remote_command(working_dir_name: &str, args: &Args, config: &Config) let result = remote_command::execute_remote_command( &args.command.clone(), config, - &format!("~/mainframer/{}", working_dir_name), + sync::project_dir_on_remote_machine(local_dir_absolute_path).as_ref(), ); let duration = start.elapsed(); @@ -109,13 +109,13 @@ fn execute_remote_command(working_dir_name: &str, args: &Args, config: &Config) result } -fn sync_after_remote_command(working_dir_name: &str, config: &Config, ignore: &Ignore) -> Result<(), String> { +fn sync_after_remote_command(working_dir_name: &Path, config: &Config, ignore: &Ignore) -> Result<(), String> { println!("Sync remote → local machine..."); let start = Instant::now(); let result = sync::sync_remote_to_local( - &working_dir_name, + working_dir_name, config, ignore, ); diff --git a/src/sync.rs b/src/sync.rs index 9a96a67..53c865d 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,17 +1,18 @@ use config::Config; use ignore::Ignore; +use std::path::Path; use std::path::PathBuf; use std::process::Command; // TODO add internal version of sync functions with closures as parameters to unit test properly. -pub fn sync_local_to_remote(local_project_dir_name: &str, config: &Config, ignore: &Ignore) -> Result<(), String> { +pub fn sync_local_to_remote(local_dir_absolute_path: &Path, config: &Config, ignore: &Ignore) -> Result<(), String> { let mut command = Command::new("rsync"); command .arg("--archive") .arg("--delete") // Create (if not exists) project dir on remote machine. - .arg(format!("--rsync-path=mkdir -p {} && rsync", project_dir_on_remote_machine(local_project_dir_name))) + .arg(format!("--rsync-path=mkdir -p {} && rsync", project_dir_on_remote_machine(local_dir_absolute_path))) .arg(format!("--compress-level={}", config.local_compression_level)); apply_exclude_from(&mut command, &ignore.common_ignore_file); @@ -24,13 +25,13 @@ pub fn sync_local_to_remote(local_project_dir_name: &str, config: &Config, ignor command.arg(format!( "{remote_machine_name}:{project_dir_on_remote_machine}", remote_machine_name = config.remote_machine_name, - project_dir_on_remote_machine = project_dir_on_remote_machine(local_project_dir_name)) + project_dir_on_remote_machine = project_dir_on_remote_machine(local_dir_absolute_path)) ); execute_rsync(&mut command) } -pub fn sync_remote_to_local(local_project_dir_name: &str, config: &Config, ignore: &Ignore) -> Result<(), String> { +pub fn sync_remote_to_local(local_dir_absolute_path: &Path, config: &Config, ignore: &Ignore) -> Result<(), String> { let mut command = Command::new("rsync"); command @@ -46,15 +47,15 @@ pub fn sync_remote_to_local(local_project_dir_name: &str, config: &Config, ignor .arg(format!( "{remote_machine_name}:{project_dir_on_remote_machine}/", remote_machine_name = config.remote_machine_name, - project_dir_on_remote_machine = project_dir_on_remote_machine(local_project_dir_name)) + project_dir_on_remote_machine = project_dir_on_remote_machine(local_dir_absolute_path)) ) .arg("./"); execute_rsync(&mut command) } -fn project_dir_on_remote_machine(local_project_dir_name: &str) -> String { - format!("~/mainframer/{}", local_project_dir_name) +pub fn project_dir_on_remote_machine(local_dir_absolute_path: &Path) -> String { + format!("~/mainframer{}", local_dir_absolute_path.to_string_lossy()) } fn apply_exclude_from(rsync_command: &mut Command, exclude_file: &Option) { diff --git a/test/common.sh b/test/common.sh index fbd9167..2bc3015 100755 --- a/test/common.sh +++ b/test/common.sh @@ -21,7 +21,7 @@ fi # Tilde expands on remote machine during ssh. # shellcheck disable=SC2088 PRIVATE_REMOTE_BUILD_ROOT_DIR="~/mainframer" -PRIVATE_REMOTE_BUILD_DIR="$PRIVATE_REMOTE_BUILD_ROOT_DIR/$PRIVATE_BUILD_DIR_NAME" +PRIVATE_REMOTE_BUILD_DIR="${PRIVATE_REMOTE_BUILD_ROOT_DIR}${DIR}/$PRIVATE_BUILD_DIR_NAME" ### Used by tests (shellcheck raises SC2034) BUILD_DIR="$DIR/$PRIVATE_BUILD_DIR_NAME"