cargo_hoist/
executables.rs1use anyhow::Result;
6use std::os::unix::fs::PermissionsExt;
7use std::path::Path;
8use tracing::instrument;
9
10#[instrument]
13pub fn exec_path(exec: &Path) -> Result<String> {
14 let is_file = std::fs::metadata(exec)?.is_file();
15 let is_exec = std::fs::metadata(exec)?.permissions().mode() & 0o111 != 0;
16 if !is_file || !is_exec {
17 anyhow::bail!("{} is not executable", exec.display());
18 }
19 let bin_file_name = exec
20 .file_name()
21 .ok_or(anyhow::anyhow!("[std] failed to extract binary name"))?;
22 let binary_name = bin_file_name
23 .to_str()
24 .ok_or(anyhow::anyhow!(
25 "[std] failed to convert binary path name to string"
26 ))?
27 .to_string();
28 tracing::debug!("retrieved binary name: {}", binary_name);
29 Ok(binary_name)
30}
31
32#[cfg(test)]
33mod tests {
34 use super::*;
35 use std::os::unix::fs::OpenOptionsExt;
36 use std::path::PathBuf;
37 use tempfile::TempDir;
38
39 #[test]
40 fn test_exec_path() {
41 let tempdir = tempfile::tempdir().unwrap();
42 let test_dir = setup_test(&tempdir, "test_exec_path");
43 let binaries = create_binaries(&test_dir);
44 let bin1 = binaries.get(0).unwrap();
45 let bin1_path = test_dir.join("target/release/binary1");
46 let bin1_exec_path = exec_path(&bin1_path).unwrap();
47 assert_eq!(bin1, &bin1_exec_path);
48 }
49
50 fn setup_test(tempdir: &TempDir, t: &str) -> PathBuf {
51 let test_dir = tempdir.path().join(t);
52 std::fs::create_dir(&test_dir).unwrap();
53 std::env::set_current_dir(&test_dir).unwrap();
54 test_dir
55 }
56
57 fn create_binaries(p: &Path) -> Vec<String> {
58 let target_dir = p.join("target/release/");
59 std::fs::create_dir_all(&target_dir).unwrap();
60 let bin1_path = target_dir.join("binary1");
61 let bin2_path = target_dir.join("binary2");
62 let opts = std::fs::OpenOptions::new()
63 .write(true)
64 .create(true)
65 .mode(0o755)
66 .open(&bin1_path)
67 .unwrap();
68 opts.sync_all().unwrap();
69 let opts = std::fs::OpenOptions::new()
70 .write(true)
71 .create(true)
72 .mode(0o755)
73 .open(&bin2_path)
74 .unwrap();
75 opts.sync_all().unwrap();
76 let mut res = Vec::with_capacity(2);
77 res.push("binary1".to_string());
78 res.push("binary2".to_string());
79 res
80 }
81}