cue-cli 0.2.0

Installed Cue command aggregator and extension dispatcher
Documentation
use std::ffi::OsString;
use std::io;
use std::path::{Path, PathBuf};

use anyhow::Context;

#[cfg(test)]
pub(crate) fn companion_binary_from_sources(
    program: &str,
    current_exe: Option<PathBuf>,
    argv0: Option<PathBuf>,
) -> Option<PathBuf> {
    current_exe
        .as_deref()
        .and_then(|path| companion_binary_for_path(path, program))
        .or_else(|| {
            argv0
                .as_deref()
                .and_then(|path| companion_binary_for_path(path, program))
        })
}

pub(crate) fn companion_binary_for_path(path: &Path, program: &str) -> Option<PathBuf> {
    let sibling = path.with_file_name(program);
    if is_executable_file(&sibling) {
        return Some(sibling);
    }

    if let Some(parent) = path.parent()
        && parent.file_name().is_some_and(|name| name == "deps")
        && let Some(bin_dir) = parent.parent()
    {
        let cargo_bin = bin_dir.join(program);
        if is_executable_file(&cargo_bin) {
            return Some(cargo_bin);
        }
    }

    None
}

pub(crate) fn argv0_path() -> anyhow::Result<Option<PathBuf>> {
    argv0_path_from_sources(std::env::args_os().next(), std::env::current_dir)
}

fn argv0_path_from_sources(
    argv0: Option<OsString>,
    current_dir: impl FnOnce() -> io::Result<PathBuf>,
) -> anyhow::Result<Option<PathBuf>> {
    let Some(argv0) = argv0 else {
        return Ok(None);
    };
    let path = PathBuf::from(argv0);
    if path.components().count() == 1 {
        return Ok(None);
    }

    let absolute = if path.is_absolute() {
        path
    } else {
        current_dir()
            .context("resolve relative argv[0] against current directory")?
            .join(path)
    };

    Ok(absolute.is_file().then_some(absolute))
}

#[cfg(unix)]
pub(crate) fn is_executable_file(path: &Path) -> bool {
    use std::os::unix::fs::PermissionsExt;

    std::fs::metadata(path)
        .map(|metadata| metadata.is_file() && metadata.permissions().mode() & 0o111 != 0)
        .unwrap_or(false)
}

#[cfg(not(unix))]
pub(crate) fn is_executable_file(path: &Path) -> bool {
    path.is_file()
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::sync::atomic::{AtomicU64, Ordering};

    static TEMP_COUNTER: AtomicU64 = AtomicU64::new(0);

    fn make_temp_bin_dir(name: &str) -> PathBuf {
        let dir = std::env::temp_dir().join(format!(
            "cue-companion-bin-test-{name}-{}-{}",
            std::process::id(),
            TEMP_COUNTER.fetch_add(1, Ordering::Relaxed)
        ));
        std::fs::create_dir_all(&dir).expect("create temp bin dir");
        dir
    }

    #[cfg(unix)]
    fn write_executable(path: &Path) {
        use std::os::unix::fs::PermissionsExt;

        std::fs::write(path, "#!/bin/sh\n").expect("write executable");
        let mut permissions = std::fs::metadata(path)
            .expect("stat executable")
            .permissions();
        permissions.set_mode(0o755);
        std::fs::set_permissions(path, permissions).expect("chmod executable");
    }

    #[cfg(not(unix))]
    fn write_executable(path: &Path) {
        std::fs::write(path, "").expect("write executable");
    }

    #[test]
    fn companion_binary_uses_current_exe_sibling() {
        let dir = make_temp_bin_dir("sibling");
        let cue = dir.join("cue");
        let tui = dir.join("cue-tui");
        write_executable(&tui);

        assert_eq!(
            companion_binary_from_sources("cue-tui", Some(cue), None),
            Some(tui)
        );

        std::fs::remove_dir_all(dir).expect("remove temp bin dir");
    }

    #[test]
    fn companion_binary_falls_back_to_argv0_sibling() {
        let dir = make_temp_bin_dir("argv0");
        let cue = dir.join("cue");
        let tui = dir.join("cue-tui");
        write_executable(&tui);

        assert_eq!(
            companion_binary_from_sources("cue-tui", None, Some(cue)),
            Some(tui)
        );

        std::fs::remove_dir_all(dir).expect("remove temp bin dir");
    }

    #[test]
    fn companion_binary_uses_cargo_bin_for_deps_path() {
        let dir = make_temp_bin_dir("cargo-deps");
        let deps = dir.join("deps");
        std::fs::create_dir_all(&deps).expect("create deps dir");
        let cue = deps.join("cue-123");
        let tui = dir.join("cue-tui");
        write_executable(&tui);

        assert_eq!(
            companion_binary_from_sources("cue-tui", Some(cue), None),
            Some(tui)
        );

        std::fs::remove_dir_all(dir).expect("remove temp bin dir");
    }

    #[cfg(unix)]
    #[test]
    fn companion_binary_rejects_non_executable_sibling() {
        let dir = make_temp_bin_dir("non-executable");
        let cue = dir.join("cue");
        let tui = dir.join("cue-tui");
        std::fs::write(&tui, "#!/bin/sh\n").expect("write non-executable sibling");

        assert_eq!(
            companion_binary_from_sources("cue-tui", Some(cue), None),
            None
        );

        std::fs::remove_dir_all(dir).expect("remove temp bin dir");
    }

    #[test]
    fn argv0_path_reports_current_dir_failure_for_relative_path() {
        let error = argv0_path_from_sources(Some(OsString::from("./cue")), || {
            Err(std::io::Error::new(
                std::io::ErrorKind::NotFound,
                "current directory was removed",
            ))
        })
        .expect_err("relative argv0 should not hide current_dir errors");

        let message = format!("{error:#}");
        assert!(message.contains("resolve relative argv[0]"));
        assert!(message.contains("current directory was removed"));
    }
}