coliru

A minimal, flexible, dotfile installer
git clone https://git.ashermorgan.net/coliru/
Log | Files | Refs | README

commit 7019ca4df776e7f42142ececf8ed2f4161334b99
parent 04f5f7cecccf4b7ca5b4f2b2dc6a2f7e4ba8b6f2
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date:   Sat,  6 Jul 2024 14:40:29 -0700

Improve error messages with anyhow

Diffstat:
MCargo.lock | 7+++++++
MCargo.toml | 3++-
Msrc/cli.rs | 2+-
Msrc/core.rs | 27+++++++++++++++++----------
Msrc/local.rs | 80++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/manifest.rs | 20++++++++++++--------
Msrc/ssh.rs | 72++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mtests/basic.rs | 9+++++----
Mtests/local.rs | 16++++++++++------
Mtests/ssh.rs | 7+++++--
10 files changed, 156 insertions(+), 87 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -52,6 +52,12 @@ dependencies = [ ] [[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] name = "bitflags" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -107,6 +113,7 @@ checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" name = "coliru" version = "0.2.0" dependencies = [ + "anyhow", "clap", "serde", "serde_yaml", diff --git a/Cargo.toml b/Cargo.toml @@ -4,8 +4,9 @@ version = "0.2.0" edition = "2021" [dependencies] +anyhow = "1.0.86" clap = { version = "4.5.7", features = ["derive"] } -shellexpand = "3.0" serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.9" +shellexpand = "3.0" tempfile = "3" diff --git a/src/cli.rs b/src/cli.rs @@ -49,7 +49,7 @@ pub fn run() { match execute_manifest_file(&manifest_path, args.tag_rules, &args.host, args.dry_run, args.copy) { Err(why) => { - eprintln!("Error: {}", why); + eprintln!("Error: {:#}", why); std::process::exit(2); }, Ok(minor_errors) => { diff --git a/src/core.rs b/src/core.rs @@ -1,7 +1,7 @@ //! Manifest execution functions +use anyhow::{Context, Result}; use std::env::set_current_dir; -use std::fmt::Display; use std::path::Path; use super::manifest::{CopyLinkOptions, RunOptions, parse_manifest_file}; use super::tags::tags_match; @@ -28,9 +28,9 @@ macro_rules! check_dry_run { /// Handles minor errors that occur during command execution and returns a bool /// indicating whether an error occurred -fn handle_error<T: Display>(result: Result<(), T>) -> bool { +fn handle_error(result: Result<()>) -> bool { if let Err(why) = result { - eprintln!(" Error: {}", why); + eprintln!(" Error: {:#}", why); return true; } false @@ -41,11 +41,13 @@ fn handle_error<T: Display>(result: Result<(), T>) -> bool { /// Returns an Err if a critical err occurs and returns a bool indicating /// whether any minor errors occurred otherwise pub fn execute_manifest_file(path: &Path, tag_rules: Vec<String>, host: &str, - dry_run: bool, copy: bool) -> Result<bool, String> { + dry_run: bool, copy: bool) -> Result<bool> { - let manifest = parse_manifest_file(path).map_err(|why| why.to_string())?; - let temp_dir = tempdir().map_err(|why| why.to_string())?; - set_current_dir(manifest.base_dir).map_err(|why| why.to_string())?; + let manifest = parse_manifest_file(path) + .context("Failed to parse manifest")?; + let temp_dir = tempdir().context("Failed to create temporary directory")?; + set_current_dir(manifest.base_dir) + .context("Failed to set working directory")?; let mut errors = false; @@ -97,12 +99,16 @@ fn execute_copies(copies: &[CopyLinkOptions], host: &str, staging_dir: &Path, if host == "" { errors |= handle_error(copy_file(&copy.src, &_dst)); } else { - errors |= handle_error(stage_file(&copy.src, &_dst, staging_dir)); + errors |= handle_error(stage_file(&copy.src, &_dst, staging_dir) + .with_context(|| { + format!("Failed to copy {} to staging directory", &copy.src) + })); } } if !dry_run { - errors |= handle_error(send_staged_files(staging_dir, host)); + errors |= handle_error(send_staged_files(staging_dir, host) + .context("Failed to transfer staged files")); } errors @@ -139,7 +145,8 @@ fn execute_runs(runs: &[RunOptions], tag_rules: &[String], host: &str, CopyLinkOptions { src: x.src.clone(), dst: x.src.clone() } }).collect(); - execute_copies(&run_copies, host, staging_dir, dry_run, step_str); + errors |= execute_copies(&run_copies, host, staging_dir, dry_run, + step_str); } for run in runs { diff --git a/src/local.rs b/src/local.rs @@ -6,8 +6,8 @@ //! run_command("echo 'Hello world'"); //! ``` +use anyhow::{bail, Context, Result}; use shellexpand::tilde; -use std::io; use std::fs; #[cfg(target_family = "unix")] use std::os::unix::fs::symlink; @@ -22,8 +22,15 @@ use std::process::Command; /// ``` /// copy_file("foo", "~/foo"); /// ``` -pub fn copy_file(src: &str, dst: &str) -> io::Result<()> { - if absolute(src)? == absolute(dst)? { return Ok(()); } +pub fn copy_file(src: &str, dst: &str) -> Result<()> { + let src_abs = absolute(src).with_context(|| { + format!("Failed to make {} absolute", src) + })?; + let dst_abs = absolute(dst).with_context(|| { + format!("Failed to make {} absolute", dst) + })?; + if src_abs == dst_abs { return Ok(()); } + let _dst = prepare_path(dst)?; fs::copy(src, _dst)?; Ok(()) @@ -38,15 +45,29 @@ pub fn copy_file(src: &str, dst: &str) -> io::Result<()> { /// link_file("bar", "~/bar"); /// ``` #[cfg(target_family = "unix")] -pub fn link_file(src: &str, dst: &str) -> io::Result<()> { - if absolute(src)? == absolute(dst)? { return Ok(()); } +pub fn link_file(src: &str, dst: &str) -> Result<()> { + let src_abs = absolute(src).with_context(|| { + format!("Failed to make {} absolute", src) + })?; + let dst_abs = absolute(dst).with_context(|| { + format!("Failed to make {} absolute", dst) + })?; + if src_abs == dst_abs { return Ok(()); } + let _dst = prepare_path(dst)?; - symlink(fs::canonicalize(src)?, _dst)?; + symlink(src_abs, _dst)?; Ok(()) } #[cfg(not(target_family = "unix"))] -pub fn link_file(src: &str, dst: &str) -> io::Result<()> { - if absolute(src)? == absolute(dst)? { return Ok(()); } +pub fn link_file(src: &str, dst: &str) -> Result<()> { + let src_abs = absolute(src).with_context(|| { + format!("Failed to make {} absolute", src) + })?; + let dst_abs = absolute(dst).with_context(|| { + format!("Failed to make {} absolute", dst) + })?; + if src_abs == dst_abs { return Ok(()); } + let _dst = prepare_path(dst)?; fs::hard_link(src, _dst)?; Ok(()) @@ -58,14 +79,18 @@ pub fn link_file(src: &str, dst: &str) -> io::Result<()> { /// ``` /// prepare_path("~/foo"); /// ``` -fn prepare_path(path: &str) -> io::Result<PathBuf> { +fn prepare_path(path: &str) -> Result<PathBuf> { let _dst: PathBuf = (&tilde(path).to_mut()).into(); if let Some(_path) = _dst.parent() { - fs::create_dir_all(_path)?; + fs::create_dir_all(_path).with_context(|| { + format!("Failed to create parent directories of {}", path) + })?; } if fs::symlink_metadata(&_dst).is_ok() { // Check for existing files, including broken symlinks - fs::remove_file(&_dst)?; + fs::remove_file(&_dst).with_context(|| { + format!("Failed to remove existing file at {}", path) + })?; } Ok(_dst) } @@ -75,25 +100,24 @@ fn prepare_path(path: &str) -> io::Result<PathBuf> { /// ``` /// run_command("echo 'Hello world'"); /// ``` -pub fn run_command(command: &str) -> Result<(), String> +pub fn run_command(command: &str) -> Result<()> { - let status; + let mut cmd; if cfg!(target_family = "unix") { - status = Command::new("sh") - .args(["-c", command]) - .status() - .map_err(|why| why.to_string())?; + cmd = Command::new("sh"); + cmd.args(["-c", command]); } else { - status = Command::new("cmd.exe") - .args(["/C", command]) - .status() - .map_err(|why| why.to_string())?; + cmd = Command::new("cmd.exe"); + cmd.args(["/C", command]); } - if status.success() { - Ok(()) - } else { - Err(format!("Process exited with {status}")) + + let status = cmd.status().with_context(|| { + format!("Failed to execute {:?}", cmd) + })?; + if !status.success() { + bail!("Process terminated unsuccessfully: {}", status); } + Ok(()) } #[cfg(test)] @@ -329,7 +353,8 @@ mod tests { let result = run_command(&format!("sh {}", src.to_str().unwrap())); assert_eq!(result.is_ok(), false); - assert_eq!(result.unwrap_err(), "Process exited with exit status: 2"); + assert_eq!(result.unwrap_err().to_string(), + "Process terminated unsuccessfully: exit status: 2"); } #[test] @@ -343,7 +368,8 @@ mod tests { let result = run_command(src.to_str().unwrap()); assert_eq!(result.is_ok(), false); - assert_eq!(result.unwrap_err(), "Process exited with exit code: 1"); + assert_eq!(result.unwrap_err().to_string(), + "Process terminated unsuccessfully: exit code: 1"); } #[test] diff --git a/src/manifest.rs b/src/manifest.rs @@ -1,5 +1,6 @@ //! Coliru manifest parsing +use anyhow::Result; use serde::Deserialize; use serde_yaml; use std::fs::read_to_string; @@ -73,10 +74,9 @@ pub struct Manifest { /// ``` /// let manifest = parse_manifest_file(Path::new("manifest.yml"))?; /// ``` -pub fn parse_manifest_file(path: &Path) -> Result<Manifest, String> { - let raw_str = read_to_string(path).map_err(|why| why.to_string())?; - let raw_manifest = serde_yaml::from_str::<RawManifest>(&raw_str) - .map_err(|why| why.to_string())?; +pub fn parse_manifest_file(path: &Path) -> Result<Manifest> { + let raw_str = read_to_string(path)?; + let raw_manifest = serde_yaml::from_str::<RawManifest>(&raw_str)?; let base_dir = match path.parent() { None => &Path::new("."), Some(p) => if p == Path::new("") { &Path::new(".") } else { p }, @@ -98,7 +98,8 @@ mod tests { let manifest_path = Path::new("examples/test/missing.yml"); let expected = "No such file or directory (os error 2)"; let actual = parse_manifest_file(manifest_path); - assert_eq!(actual, Err(String::from(expected))); + assert_eq!(actual.is_ok(), false); + assert_eq!(actual.unwrap_err().to_string(), expected); } #[test] @@ -107,7 +108,8 @@ mod tests { let manifest_path = Path::new("examples/test/missing.yml"); let exp = "The system cannot find the file specified. (os error 2)"; let actual = parse_manifest_file(manifest_path); - assert_eq!(actual, Err(String::from(exp))); + assert_eq!(actual.is_ok(), false); + assert_eq!(actual.unwrap_err().to_string(), exp); } #[test] @@ -115,7 +117,8 @@ mod tests { let manifest_path = Path::new("examples/test/invalid.yml"); let exp = "steps[0].copy[0]: missing field `src` at line 5 column 7"; let actual = parse_manifest_file(manifest_path); - assert_eq!(actual, Err(String::from(exp))); + assert_eq!(actual.is_ok(), false); + assert_eq!(actual.unwrap_err().to_string(), exp); } #[test] @@ -180,6 +183,7 @@ mod tests { base_dir: PathBuf::from("examples/test"), }; let actual = parse_manifest_file(manifest_path); - assert_eq!(actual, Ok(expected)); + assert_eq!(actual.is_ok(), true); + assert_eq!(actual.unwrap(), expected); } } diff --git a/src/ssh.rs b/src/ssh.rs @@ -11,6 +11,7 @@ //! send_command("bash ~/foo.sh", host); //! ``` +use anyhow::{bail, anyhow, Context, Result}; use shellexpand::tilde_with_context; use std::fs::{read_dir, remove_dir_all}; use std::path::{MAIN_SEPARATOR_STR, Path, PathBuf}; @@ -45,9 +46,7 @@ pub fn resolve_path(src: &str, dir: &str) -> String { /// stage_file("bar", "/bar", staging_dir); /// stage_file("baz", "baz", staging_dir); /// ``` -pub fn stage_file(src: &str, dst: &str, staging_dir: &Path) -> Result<(), - String> { - +pub fn stage_file(src: &str, dst: &str, staging_dir: &Path) -> Result<()> { // Staging directories are used to copy multiple files at once while // automatically creating missing directories on the remote machine. The // example code above produces the following staging directory layout: @@ -79,14 +78,16 @@ pub fn stage_file(src: &str, dst: &str, staging_dir: &Path) -> Result<(), // path separator. (Duplicate slashes are ignored on Unix). let root = PathBuf::from(match _dst.iter().next() { Some(x) => Ok(x), - None => Err(String::from("Destination path does not have root")), + None => Err(anyhow!("Failed to get root of {}", _dst.display())), }?).join(MAIN_SEPARATOR_STR); - _dst = root_dir.join(_dst.strip_prefix(root) - .map_err(|why| why.to_string())?); + + let dst_without_root = _dst.strip_prefix(root).with_context(|| { + format!("Failed to strip root from {}", _dst.display()) + })?; + _dst = root_dir.join(dst_without_root); } copy_file(src, _dst.to_string_lossy().to_mut()) - .map_err(|why| why.to_string()) } /// Transfers the files in an SCP staging directory to a remote machine @@ -98,16 +99,22 @@ pub fn stage_file(src: &str, dst: &str, staging_dir: &Path) -> Result<(), /// ``` /// send_staged_files(Path::new("/tmp/staging"), "user@hostname"); /// ``` -pub fn send_staged_files(staging_dir: &Path, host: &str) -> Result<(), String> { +pub fn send_staged_files(staging_dir: &Path, host: &str) -> Result<()> { let home_dir = staging_dir.join("home"); if home_dir.exists() { send_dir(home_dir.to_string_lossy().to_mut(), "~", host)?; - remove_dir_all(home_dir).map_err(|why| why.to_string())?; + remove_dir_all(&home_dir).with_context(|| { + format!("Failed to remove staging dir {} after use", + &home_dir.display()) + })?; } let root_dir = staging_dir.join("root"); if root_dir.exists() { send_dir(root_dir.to_string_lossy().to_mut(), "/", host)?; - remove_dir_all(root_dir).map_err(|why| why.to_string())?; + remove_dir_all(&root_dir).with_context(|| { + format!("Failed to remove staging dir {} after use", + &root_dir.display()) + })?; } Ok(()) } @@ -120,12 +127,17 @@ pub fn send_staged_files(staging_dir: &Path, host: &str) -> Result<(), String> { /// ``` /// send_dir("new_home", "~/", "user@hostname"); /// ``` -fn send_dir(src: &str, dst: &str, host: &str) -> Result<(), String> { +fn send_dir(src: &str, dst: &str, host: &str) -> Result<()> { // To avoid the source directory being copied as a subdirectory of the // destination directory, we must send the contents of the directory // item by item. - for item in read_dir(&src).map_err(|why| why.to_string())? { - let _src = item.map_err(|why| why.to_string())?.path(); + let items = read_dir(&src).with_context(|| { + format!("Failed to list contents of {}", src) + })?; + for item in items { + let _src = item.with_context(|| { + format!("Failed to list contents of {}", src) + })?.path(); let mut cmd = Command::new("scp"); if host == "test@localhost" { @@ -134,9 +146,11 @@ fn send_dir(src: &str, dst: &str, host: &str) -> Result<(), String> { } cmd.args(["-r", &_src.to_string_lossy(), &format!("{host}:{dst}")]); - let status = cmd.status().map_err(|why| why.to_string())?; + let status = cmd.status().with_context(|| { + format!("Failed to execute {:?}", cmd) + })?; if !status.success() { - return Err(format!("SCP exited with {status}")); + bail!("SCP terminated unsuccessfully: {}", status); } } Ok(()) @@ -149,7 +163,7 @@ fn send_dir(src: &str, dst: &str, host: &str) -> Result<(), String> { /// ``` /// send_command("echo 'Hello World'"); /// ``` -pub fn send_command(command: &str, host: &str) -> Result<(), String> { +pub fn send_command(command: &str, host: &str) -> Result<()> { let mut cmd = Command::new("ssh"); if host == "test@localhost" { // SSH options and port for test server hard coded for now @@ -157,9 +171,11 @@ pub fn send_command(command: &str, host: &str) -> Result<(), String> { } cmd.args([host, command]); - let status = cmd.status().map_err(|why| why.to_string())?; + let status = cmd.status().with_context(|| { + format!("Failed to execute {:?}", cmd) + })?; if !status.success() { - return Err(format!("SSH exited with {status}")); + bail!("SSH terminated unsuccessfully: {}", status); } Ok(()) } @@ -215,7 +231,7 @@ mod tests { let result = stage_file(src.to_str().unwrap(), dst, staging); - assert_eq!(result, Ok(())); + assert_eq!(result.is_ok(), true); assert_eq!(dst_real.exists(), true); assert_eq!(read_file(&dst_real), "contents of foo"); } @@ -233,7 +249,7 @@ mod tests { let result = stage_file(src.to_str().unwrap(), dst, staging); - assert_eq!(result, Ok(())); + assert_eq!(result.is_ok(), true); assert_eq!(dst_real.exists(), true); assert_eq!(read_file(&dst_real), "contents of foo"); } @@ -250,7 +266,7 @@ mod tests { let result = stage_file(src.to_str().unwrap(), dst, staging); - assert_eq!(result, Ok(())); + assert_eq!(result.is_ok(), true); assert_eq!(dst_real.exists(), true); assert_eq!(read_file(&dst_real), "contents of foo"); } @@ -262,7 +278,7 @@ mod tests { let result = send_staged_files(&tmp.local, SSH_HOST); - assert_eq!(result, Ok(())); + assert_eq!(result.is_ok(), true); } #[test] @@ -281,7 +297,7 @@ mod tests { let dst_foo = tmp.ssh.join("foo"); let dst_bar = tmp.ssh.join("dir").join("bar"); - assert_eq!(result, Ok(())); + assert_eq!(result.is_ok(), true); assert_eq!(dst_foo.exists(), true); assert_eq!(read_file(&dst_foo), "contents of foo"); assert_eq!(dst_bar.exists(), true); @@ -307,7 +323,7 @@ mod tests { let dst_foo = tmp.ssh.join("foo"); let dst_bar = tmp.ssh.join("dir").join("bar"); - assert_eq!(result, Ok(())); + assert_eq!(result.is_ok(), true); assert_eq!(dst_foo.exists(), true); assert_eq!(read_file(&dst_foo), "contents of foo"); assert_eq!(dst_bar.exists(), true); @@ -330,7 +346,7 @@ mod tests { let result = send_dir(tmp.local.to_str().unwrap(), dst, SSH_HOST); - assert_eq!(result, Ok(())); + assert_eq!(result.is_ok(), true); assert_eq!(dst_foo.exists(), true); assert_eq!(read_file(&dst_foo), "contents of foo"); assert_eq!(dst_bar.exists(), true); @@ -354,7 +370,7 @@ mod tests { let result = send_dir(tmp.local.to_str().unwrap(), dst, SSH_HOST); - assert_eq!(result, Ok(())); + assert_eq!(result.is_ok(), true); assert_eq!(dst_foo.exists(), true); assert_eq!(read_file(&dst_foo), "contents of foo"); assert_eq!(dst_bar.exists(), true); @@ -381,7 +397,7 @@ mod tests { let result = send_dir(tmp.local.to_str().unwrap(), dst, SSH_HOST); - assert_eq!(result, Ok(())); + assert_eq!(result.is_ok(), true); assert_eq!(dst_foo.exists(), true); assert_eq!(read_file(&dst_foo), "old contents of foo"); assert_eq!(dst_bar.exists(), true); @@ -401,7 +417,7 @@ mod tests { let result = send_command(&cmd, SSH_HOST); - assert_eq!(result, Ok(())); + assert_eq!(result.is_ok(), true); assert_eq!(dst_real.exists(), true); assert_eq!(read_file(&dst_real), "contents of foo\n"); } diff --git a/tests/basic.rs b/tests/basic.rs @@ -64,7 +64,7 @@ fn test_basic_empty_manifest() { cmd.args(["manifest.yml"]); write_file(&dirs.local.join("manifest.yml"), ""); - let expected = "Error: missing field `steps`\n"; + let expected = "Error: Failed to parse manifest: missing field `steps`\n"; let (stdout, stderr, exitcode) = run_command(&mut cmd); assert_eq!(&stderr, expected); assert_eq!(&stdout, ""); @@ -77,7 +77,8 @@ fn test_basic_missing_manifest() { let (_dirs, mut cmd) = setup_e2e_local("test_basic_missing_manifest"); cmd.args(["missing.yml"]); - let expected = "Error: No such file or directory (os error 2)\n"; + let expected = "Error: Failed to parse manifest: No such file or directory \ + (os error 2)\n"; let (stdout, stderr, exitcode) = run_command(&mut cmd); assert_eq!(&stderr, expected); assert_eq!(&stdout, ""); @@ -90,8 +91,8 @@ fn test_basic_missing_manifest() { let (_dirs, mut cmd) = setup_e2e_local("test_basic_missing_manifest"); cmd.args(["missing.yml"]); - let expected = "Error: The system cannot find the file specified. \ - (os error 2)\n"; + let expected = "Error: Failed to parse manifest: The system cannot find \ + the file specified. (os error 2)\n"; let (stdout, stderr, exitcode) = run_command(&mut cmd); assert_eq!(&stderr, expected); assert_eq!(&stdout, ""); diff --git a/tests/local.rs b/tests/local.rs @@ -275,7 +275,8 @@ fn test_local_run_failure() { [2/3] Link vimrc to ~/.vimrc [2/3] Run sh script.sh arg1 linux "; - let expected_stderr = " Error: Process exited with exit status: 1\n"; + let expected_stderr = " Error: Process terminated unsuccessfully: \ + exit status: 1\n"; let (stdout, stderr, exitcode) = run_command(&mut cmd); assert_eq!(&stderr, expected_stderr); assert_eq!(&stdout, expected_stdout); @@ -307,7 +308,8 @@ fn test_local_run_failure() { [3/3] Link vimrc to _vimrc [3/3] Run script.bat arg1 windows "; - let expected_stderr = " Error: Process exited with exit code: 1\n"; + let expected_stderr = " Error: Process terminated unsuccessfully: \ + exit code: 1\n"; let (stdout, stderr, exitcode) = run_command(&mut cmd); assert_eq!(&stderr, expected_stderr); assert_eq!(&stdout, expected_stdout); @@ -331,7 +333,7 @@ fn test_local_run_failure() { fn test_local_missing_file() { let (dirs, mut cmd) = setup_e2e_local("test_local_missing_file"); cmd.args(["manifest.yml", "-t", "linux"]); - remove_file(&dirs.local.join("vimrc")).unwrap(); + remove_file(&dirs.local.join("gitconfig")).unwrap(); let expected_stdout = "\ [1/3] Copy gitconfig to ~/.gitconfig @@ -348,12 +350,14 @@ script.sh called with arg1 linux // Assert files are correctly copied/linked/run write_file(&dirs.local.join("bashrc"), "bash #2\n"); - write_file(&dirs.local.join("gitconfig"), "git #2\n"); + write_file(&dirs.local.join("vimrc"), "vim #2\n"); let bash_contents = read_file(&dirs.home.join(".bashrc")); - let git_contents = read_file(&dirs.home.join(".gitconfig")); + let vim1_contents = read_file(&dirs.home.join(".vimrc")); + let vim2_exists = dirs.home.join("_vimrc").exists(); let log_contents = read_file(&dirs.local.join("log.txt")); assert_eq!(bash_contents, "bash #2\n"); - assert_eq!(git_contents, "git #1\n"); + assert_eq!(vim1_contents, "vim #2\n"); + assert_eq!(vim2_exists, false); assert_eq!(log_contents, "script.sh called with arg1 linux\n"); } diff --git a/tests/ssh.rs b/tests/ssh.rs @@ -1,3 +1,5 @@ +#![allow(unused_imports)] + //! End to end tests that test installation behavior on a remote machine via SSH mod test_utils; @@ -176,7 +178,7 @@ fn test_ssh_run_failure() { [2/3] Copy test_ssh_run_failure/script.sh to {SSH_HOST}:~/.coliru/test_ssh_run_failure/script.sh [2/3] Run sh test_ssh_run_failure/script.sh arg1 linux on {SSH_HOST} "); - let expected_stderr = " Error: SSH exited with exit status: 1\n"; + let expected_stderr = " Error: SSH terminated unsuccessfully: exit status: 1\n"; let (stdout, stderr, exitcode) = run_command(&mut cmd); assert_eq!(&stderr, expected_stderr); assert_eq!(&stdout, &expected_stdout); @@ -208,7 +210,8 @@ fn test_ssh_missing_file() { [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)\n"; + let expected_stderr = " Error: Failed to copy vimrc to staging directory: \ + No such file or directory (os error 2)\n"; let (stdout, stderr, exitcode) = run_command(&mut cmd); assert_eq!(&stderr, expected_stderr); assert_eq!(&stdout, &expected_stdout);