commit d53e8d5f6a9eb93cbc22f1374e36a75f6e8a83d0
parent 314cf9940496f884d17acb59b14578268c111fe2
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date: Thu, 4 Jul 2024 13:35:18 -0700
Implement run command for remote hosts
Diffstat:
4 files changed, 79 insertions(+), 75 deletions(-)
diff --git a/src/core.rs b/src/core.rs
@@ -3,7 +3,7 @@ use std::path::Path;
use super::manifest::{CopyLinkOptions, RunOptions, parse_manifest_file};
use super::tags::tags_match;
use super::local::{copy_file, link_file, run_script};
-use super::ssh::{send_staged_files, stage_file};
+use super::ssh::{send_command, send_staged_files, stage_file};
use tempfile::tempdir;
/// Execute the steps in a coliru manifest file according to a set of tag rules
@@ -34,47 +34,30 @@ pub fn execute_manifest_file(path: &Path, tag_rules: Vec<String>, host: &str,
let step_str = format!("[{}/{}]", i+1, manifest.steps.len());
- if host == "" {
- execute_copies(&step.copy, dry_run, &step_str);
- } else {
- execute_copies_remote(&step.copy, host, temp_dir.path(), dry_run,
- &step_str);
- }
+ execute_copies(&step.copy, host, temp_dir.path(), dry_run, &step_str);
+
if !copy && host == "" {
execute_links(&step.link, dry_run, &step_str);
- } else if host != "" {
- execute_copies_remote(&step.link, host, temp_dir.path(), dry_run,
- &step_str);
} else {
- execute_copies(&step.link, dry_run, &step_str);
- }
- execute_runs(&step.run, &tag_rules, host, dry_run, &step_str);
- }
-}
-
-/// Execute a set of copy commands on the local machine
-fn execute_copies(copies: &[CopyLinkOptions], dry_run: bool, step_str: &str) {
- for copy in copies {
- print!("{} Copy {} to {}", step_str, copy.src, copy.dst);
-
- if dry_run {
- println!(" (DRY RUN)");
- continue;
+ execute_copies(&step.link, host, temp_dir.path(), dry_run,
+ &step_str);
}
- println!("");
- if let Err(why) = copy_file(©.src, ©.dst) {
- eprintln!(" Error: {}", why);
- }
+ execute_runs(&step.run, &tag_rules, host, temp_dir.path(), dry_run,
+ &step_str);
}
}
-/// Execute a set of copy commands on a remote machine
-fn execute_copies_remote(copies: &[CopyLinkOptions], host: &str,
- staging_dir: &Path, dry_run: bool, step_str: &str) {
+/// Execute a set of copy commands
+fn execute_copies(copies: &[CopyLinkOptions], host: &str, staging_dir: &Path,
+ dry_run: bool, step_str: &str) {
for copy in copies {
- print!("{} Copy {} to {}:{}", step_str, copy.src, host, copy.dst);
+ if host == "" {
+ print!("{} Copy {} to {}", step_str, copy.src, copy.dst);
+ } else {
+ print!("{} Copy {} to {}:{}", step_str, copy.src, host, copy.dst);
+ }
if dry_run {
println!(" (DRY RUN)");
@@ -82,8 +65,14 @@ fn execute_copies_remote(copies: &[CopyLinkOptions], host: &str,
}
println!("");
- if let Err(why) = stage_file(©.src, ©.dst, staging_dir) {
- eprintln!(" Error: {}", why);
+ if host == "" {
+ if let Err(why) = copy_file(©.src, ©.dst) {
+ eprintln!(" Error: {}", why);
+ }
+ } else {
+ if let Err(why) = stage_file(©.src, ©.dst, staging_dir) {
+ eprintln!(" Error: {}", why);
+ }
}
}
@@ -94,7 +83,7 @@ fn execute_copies_remote(copies: &[CopyLinkOptions], host: &str,
}
}
-/// Execute a set of link commands on the local machine
+/// Execute a set of link commands
fn execute_links(links: &[CopyLinkOptions], dry_run: bool, step_str: &str) {
for link in links {
print!("{} Link {} to {}", step_str, link.src, link.dst);
@@ -111,9 +100,21 @@ fn execute_links(links: &[CopyLinkOptions], dry_run: bool, step_str: &str) {
}
}
-/// Execute a set of run commands on the local machine
+/// Execute a set of run commands
fn execute_runs(runs: &[RunOptions], tag_rules: &[String], host: &str,
- dry_run: bool, step_str: &str) {
+ staging_dir: &Path, dry_run: bool, step_str: &str) {
+
+ if !dry_run && host != "" {
+ for run in runs {
+ if let Err(why) = stage_file(&run.src, &run.src, staging_dir) {
+ eprintln!("Error: {}", why);
+ }
+ }
+
+ if let Err(why) = send_staged_files(staging_dir, host) {
+ eprintln!("Error: {}", why);
+ }
+ }
for run in runs {
let postfix = run.postfix.replace("$COLIRU_RULES", &tag_rules.join(" "));
@@ -135,7 +136,11 @@ fn execute_runs(runs: &[RunOptions], tag_rules: &[String], host: &str,
eprintln!(" Error: {}", why);
}
} else {
- eprintln!(" Error: not implemented");
+ let cmd = format!("cd .coliru && {} {} {}", &run.prefix, &run.src,
+ &postfix);
+ if let Err(why) = send_command(&cmd, host) {
+ eprintln!(" Error: {}", why);
+ }
}
}
}
diff --git a/src/ssh.rs b/src/ssh.rs
@@ -22,7 +22,7 @@ pub fn stage_file(src: &str, dst: &str, staging_dir: &Path) -> Result<(), String
.into();
// Resolve relative paths to home staging directory:
- _dst = home_dir.join(_dst);
+ _dst = home_dir.join(".coliru").join(_dst);
// Resolve other absolute paths to root staging directory:
if !_dst.starts_with(home_dir) {
@@ -88,7 +88,6 @@ pub fn send_command(command: &str, host: &str) -> Result<(), String> {
// SSH options and port for test server hard coded for now
cmd.args(["-o", "StrictHostKeyChecking=no", "-p", "2222"]);
}
- println!("{host} {command} running");
cmd.args([host, command]);
let status = cmd.status().map_err(|why| why.to_string())?;
@@ -130,7 +129,8 @@ mod tests {
let src = tmp.local.join("foo");
let dst = "dir/bar";
- let dst_real = tmp.local.join("home").join("dir").join("bar");
+ let dst_real = tmp.local.join("home").join(".coliru").join("dir")
+ .join("bar");
let staging = &tmp.local;
write_file(&src, "contents of foo");
diff --git a/tests/common/mod.rs b/tests/common/mod.rs
@@ -115,7 +115,7 @@ pub fn setup_e2e_ssh(name: &str) -> (TempDirs, Command) {
/// scripts/*) will be replaced with the value of home_dir and script_dir
/// respectively to ensures that dotfiles are isolated across tests when
/// necessary.
-pub fn copy_manifest(dir: &Path, home_dir: &str, script_dir: &str) {
+fn copy_manifest(dir: &Path, home_dir: &str, script_dir: &str) {
let examples = env::current_exe().unwrap().parent().unwrap().to_path_buf()
.join("../../../examples/test");
diff --git a/tests/ssh.rs b/tests/ssh.rs
@@ -12,27 +12,27 @@ fn test_ssh_standard() {
let (dirs, mut cmd) = setup_e2e_ssh("test_ssh_standard");
cmd.args(["manifest.yml", "-t", "linux"]);
- let expected_stdout = format!("\
+ let expected = format!("\
[1/3] Copy gitconfig to {SSH_HOST}:~/test_ssh_standard/.gitconfig
[2/3] Copy bashrc to {SSH_HOST}:~/test_ssh_standard/.bashrc
[2/3] Copy vimrc to {SSH_HOST}:~/test_ssh_standard/.vimrc
[2/3] Run sh test_ssh_standard/script.sh arg1 linux on {SSH_HOST}
+script.sh called with arg1 linux
");
- let expected_stderr = " Error: not implemented\n";
- assert_eq!(&stderr_to_string(&mut cmd), expected_stderr);
- assert_eq!(stdout_to_string(&mut cmd), expected_stdout);
+ assert_eq!(&stderr_to_string(&mut cmd), "");
+ assert_eq!(stdout_to_string(&mut cmd), expected);
// Assert files are correctly copied/run
let bash_contents = read_file(&dirs.ssh.join(".bashrc"));
let git_contents = read_file(&dirs.ssh.join(".gitconfig"));
let vim1_contents = read_file(&dirs.ssh.join(".vimrc"));
let vim2_exists = dirs.ssh.join("_vimrc").exists();
- // let log_contents = read_file(&dirs.local.join("log.txt"));
+ let log_contents = read_file(&dirs.ssh.join("log.txt"));
assert_eq!(bash_contents, "bash #1\n");
assert_eq!(git_contents, "git #1\n");
assert_eq!(vim1_contents, "vim #1\n");
assert_eq!(vim2_exists, false);
- // assert_eq!(log_contents, "script.sh called with arg1 linux\n");
+ assert_eq!(log_contents, "script.sh called with arg1 linux\n");
}
#[test]
@@ -41,26 +41,26 @@ fn test_ssh_run_alternate_tag_rules_1() {
let (dirs, mut cmd) = setup_e2e_ssh("test_ssh_run_alternate_tag_rules_1");
cmd.args(["manifest.yml", "-t", "linux", "^windows"]);
- let expected_stdout = format!("\
+ let expected = format!("\
[2/3] Copy bashrc to {SSH_HOST}:~/test_ssh_run_alternate_tag_rules_1/.bashrc
[2/3] Copy vimrc to {SSH_HOST}:~/test_ssh_run_alternate_tag_rules_1/.vimrc
[2/3] Run sh test_ssh_run_alternate_tag_rules_1/script.sh arg1 linux ^windows on {SSH_HOST}
+script.sh called with arg1 linux ^windows
");
- let expected_stderr = " Error: not implemented\n";
- assert_eq!(&stderr_to_string(&mut cmd), expected_stderr);
- assert_eq!(stdout_to_string(&mut cmd), expected_stdout);
+ assert_eq!(&stderr_to_string(&mut cmd), "");
+ assert_eq!(stdout_to_string(&mut cmd), expected);
// Assert files are correctly copied/run
let bash_contents = read_file(&dirs.ssh.join(".bashrc"));
let git_exists = dirs.ssh.join(".gitconfig").exists();
let vim1_contents = read_file(&dirs.ssh.join(".vimrc"));
let vim2_exists = dirs.ssh.join("_vimrc").exists();
- // let log_contents = read_file(&dirs.local.join("log.txt"));
+ let log_contents = read_file(&dirs.ssh.join("log.txt"));
assert_eq!(bash_contents, "bash #1\n");
assert_eq!(git_exists, false);
assert_eq!(vim1_contents, "vim #1\n");
assert_eq!(vim2_exists, false);
- // assert_eq!(log_contents, "script.sh called with arg1 linux ^windows\n");
+ assert_eq!(log_contents, "script.sh called with arg1 linux ^windows\n");
}
#[test]
@@ -69,27 +69,27 @@ fn test_ssh_run_alternate_tag_rules_2() {
let (dirs, mut cmd) = setup_e2e_ssh("test_ssh_run_alternate_tag_rules_2");
cmd.args(["manifest.yml", "-t", "macos"]);
- let expected_stdout = format!("\
+ let expected = format!("\
[1/3] Copy gitconfig to {SSH_HOST}:~/test_ssh_run_alternate_tag_rules_2/.gitconfig
[2/3] Copy bashrc to {SSH_HOST}:~/test_ssh_run_alternate_tag_rules_2/.bashrc
[2/3] Copy vimrc to {SSH_HOST}:~/test_ssh_run_alternate_tag_rules_2/.vimrc
[2/3] Run sh test_ssh_run_alternate_tag_rules_2/script.sh arg1 macos on {SSH_HOST}
+script.sh called with arg1 macos
");
- let expected_stderr = " Error: not implemented\n";
- assert_eq!(&stderr_to_string(&mut cmd), expected_stderr);
- assert_eq!(stdout_to_string(&mut cmd), expected_stdout);
+ assert_eq!(&stderr_to_string(&mut cmd), "");
+ assert_eq!(stdout_to_string(&mut cmd), expected);
// Assert files are correctly copied/run
let bash_contents = read_file(&dirs.ssh.join(".bashrc"));
let git_contents = read_file(&dirs.ssh.join(".gitconfig"));
let vim1_contents = read_file(&dirs.ssh.join(".vimrc"));
let vim2_exists = dirs.ssh.join("_vimrc").exists();
- // let log_contents = read_file(&dirs.local.join("log.txt"));
+ let log_contents = read_file(&dirs.ssh.join("log.txt"));
assert_eq!(bash_contents, "bash #1\n");
assert_eq!(git_contents, "git #1\n");
assert_eq!(vim1_contents, "vim #1\n");
assert_eq!(vim2_exists, false);
- // assert_eq!(log_contents, "script.sh called with arg1 macos\n");
+ assert_eq!(log_contents, "script.sh called with arg1 macos\n");
}
#[test]
@@ -111,12 +111,12 @@ fn test_ssh_dry_run() {
let git_exists = dirs.ssh.join(".gitconfig").exists();
let vim1_exists = dirs.ssh.join(".vimrc").exists();
let vim2_exists = dirs.ssh.join("_vimrc").exists();
- // let log_exists = dirs.local.join("log.txt").exists();
+ let log_exists = dirs.ssh.join("log.txt").exists();
assert_eq!(bash_exists, false);
assert_eq!(git_exists, false);
assert_eq!(vim1_exists, false);
assert_eq!(vim2_exists, false);
- // assert_eq!(log_exists, false);
+ assert_eq!(log_exists, false);
}
#[test]
@@ -125,27 +125,27 @@ fn test_ssh_copy() {
let (dirs, mut cmd) = setup_e2e_ssh("test_ssh_copy");
cmd.args(["manifest.yml", "--copy", "-t", "linux"]);
- let expected_stdout = format!("\
+ let expected = format!("\
[1/3] Copy gitconfig to {SSH_HOST}:~/test_ssh_copy/.gitconfig
[2/3] Copy bashrc to {SSH_HOST}:~/test_ssh_copy/.bashrc
[2/3] Copy vimrc to {SSH_HOST}:~/test_ssh_copy/.vimrc
[2/3] Run sh test_ssh_copy/script.sh arg1 linux on {SSH_HOST}
+script.sh called with arg1 linux
");
- let expected_stderr = " Error: not implemented\n";
- assert_eq!(&stderr_to_string(&mut cmd), expected_stderr);
- assert_eq!(stdout_to_string(&mut cmd), expected_stdout);
+ assert_eq!(&stderr_to_string(&mut cmd), "");
+ assert_eq!(stdout_to_string(&mut cmd), expected);
// Assert files are correctly copied/run
let bash_contents = read_file(&dirs.ssh.join(".bashrc"));
let git_contents = read_file(&dirs.ssh.join(".gitconfig"));
let vim1_contents = read_file(&dirs.ssh.join(".vimrc"));
let vim2_exists = dirs.ssh.join("_vimrc").exists();
- // let log_contents = read_file(&dirs.local.join("log.txt"));
+ let log_contents = read_file(&dirs.ssh.join("log.txt"));
assert_eq!(bash_contents, "bash #1\n");
assert_eq!(git_contents, "git #1\n");
assert_eq!(vim1_contents, "vim #1\n");
assert_eq!(vim2_exists, false);
- // assert_eq!(log_contents, "script.sh called with arg1 linux\n");
+ assert_eq!(log_contents, "script.sh called with arg1 linux\n");
}
#[test]
@@ -153,7 +153,7 @@ fn test_ssh_copy() {
fn test_ssh_run_failure() {
let (dirs, mut cmd) = setup_e2e_ssh("test_ssh_run_failure");
cmd.args(["manifest.yml", "-t", "linux"]);
- write_file(&dirs.local.join("script.sh"), "exit 1");
+ write_file(&dirs.local.join("test_ssh_run_failure/script.sh"), "exit 1");
let expected_stdout = format!("\
[1/3] Copy gitconfig to {SSH_HOST}:~/test_ssh_run_failure/.gitconfig
@@ -161,7 +161,7 @@ fn test_ssh_run_failure() {
[2/3] Copy vimrc to {SSH_HOST}:~/test_ssh_run_failure/.vimrc
[2/3] Run sh test_ssh_run_failure/script.sh arg1 linux on {SSH_HOST}
");
- let expected_stderr = " Error: not implemented\n";
+ let expected_stderr = " Error: SSH exited with exit status: 1\n";
assert_eq!(&stderr_to_string(&mut cmd), expected_stderr);
assert_eq!(stdout_to_string(&mut cmd), expected_stdout);
@@ -188,18 +188,17 @@ fn test_ssh_missing_file() {
[2/3] Copy bashrc to {SSH_HOST}:~/test_ssh_missing_file/.bashrc
[2/3] Copy vimrc to {SSH_HOST}:~/test_ssh_missing_file/.vimrc
[2/3] Run sh test_ssh_missing_file/script.sh arg1 linux on {SSH_HOST}
+script.sh called with arg1 linux
");
- let expected_stderr = " Error: No such file or directory (os error 2)
- Error: not implemented
-";
+ let expected_stderr = " Error: No such file or directory (os error 2)\n";
assert_eq!(&stderr_to_string(&mut cmd), expected_stderr);
assert_eq!(stdout_to_string(&mut cmd), expected_stdout);
// Assert files are correctly copied/run
let bash_contents = read_file(&dirs.ssh.join(".bashrc"));
let git_contents = read_file(&dirs.ssh.join(".gitconfig"));
- // let log_contents = read_file(&dirs.ssh.join("log.txt"));
+ let log_contents = read_file(&dirs.ssh.join("log.txt"));
assert_eq!(bash_contents, "bash #1\n");
assert_eq!(git_contents, "git #1\n");
- // assert_eq!(log_contents, "script.sh called with arg1 linux\n");
+ assert_eq!(log_contents, "script.sh called with arg1 linux\n");
}