kcode-rust-bins 3.0.0

Author, locally publish, and run small Rust binaries
Documentation
use std::fs::{self, File as FsFile, OpenOptions};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};

#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;

use semver::{Version, VersionReq};

use crate::model::{Error, Result, validate_name};

const LOCKS_DIRECTORY: &str = ".locks";
static UNIQUE_COUNTER: AtomicU64 = AtomicU64::new(0);

pub(crate) struct Publication {
    pub(crate) version: Version,
    pub(crate) executable: PathBuf,
}

pub(crate) fn publish(root: &Path, name: &str, version: &str, executable: &[u8]) -> Result<()> {
    validate_name(name)?;
    let version = stable_version(version)?;
    if executable.is_empty() {
        return Err(Error::new("invalid_publication", "the executable is empty"));
    }

    let root = checked_root(root, true)?;
    let locks = root.join(LOCKS_DIRECTORY);
    create_checked_directory(&locks, "publication lock root")?;
    let name_locks = locks.join(name);
    create_checked_directory(&name_locks, "binary publication lock directory")?;
    let _lock = lock_file(&name_locks.join(".lock"))?;

    let binary_root = root.join(name);
    create_checked_directory(&binary_root, "published binary directory")?;
    let destination = binary_root.join(format!("v{version}"));
    if path_exists(&destination)? {
        return Err(Error::new(
            "already_published",
            format!("binary {name:?} version {version} is already published"),
        ));
    }

    let staging = binary_root.join(format!(".staging-{}", unique_id()));
    fs::create_dir(&staging)
        .map_err(|error| Error::io("create staged binary publication", &staging, error))?;
    let result = (|| {
        let executable_path = staging.join(name);
        let mut file = OpenOptions::new()
            .write(true)
            .create_new(true)
            .open(&executable_path)
            .map_err(|error| {
                Error::io(
                    "create staged published executable",
                    &executable_path,
                    error,
                )
            })?;
        file.write_all(executable).map_err(|error| {
            Error::io("write staged published executable", &executable_path, error)
        })?;
        file.sync_all().map_err(|error| {
            Error::io("sync staged published executable", &executable_path, error)
        })?;
        set_executable(&executable_path)?;
        sync_directory(&staging)?;

        if path_exists(&destination)? {
            return Err(Error::new(
                "already_published",
                format!("binary {name:?} version {version} is already published"),
            ));
        }
        fs::rename(&staging, &destination)
            .map_err(|error| Error::io("install binary publication", &destination, error))?;
        sync_directory(&binary_root)
    })();
    if result.is_err() {
        let _ = fs::remove_dir_all(&staging);
    }
    result
}

pub(crate) fn resolve(root: &Path, name: &str, selector: &str) -> Result<Publication> {
    validate_name(name)?;
    if selector.is_empty() || selector.len() > 512 || selector.contains(['/', '\0']) {
        return Err(Error::new(
            "invalid_selector",
            "invalid binary version selector",
        ));
    }

    let exact = selector
        .strip_prefix('v')
        .and_then(|value| Version::parse(value).ok())
        .filter(|version| {
            version.to_string() == selector.trim_start_matches('v')
                && version.pre.is_empty()
                && version.build.is_empty()
        });
    let requirement = if exact.is_none() {
        let value = selector.strip_prefix('v').unwrap_or(selector);
        Some(VersionReq::parse(value).map_err(|error| {
            Error::new(
                "invalid_selector",
                format!("invalid Cargo-compatible version requirement: {error}"),
            )
        })?)
    } else {
        None
    };

    let root = checked_root(root, false)?;
    let binary_root = checked_directory(&root.join(name), "published binary")?;
    let entries = fs::read_dir(&binary_root)
        .map_err(|error| Error::io("list published binary versions", &binary_root, error))?;
    let mut selected = None;
    for entry in entries {
        let entry =
            entry.map_err(|error| Error::io("read published binary entry", &binary_root, error))?;
        let path = entry.path();
        let metadata = fs::symlink_metadata(&path)
            .map_err(|error| Error::io("inspect published binary version", &path, error))?;
        if metadata.file_type().is_symlink() || !metadata.is_dir() {
            continue;
        }
        let Some(directory) = entry.file_name().to_str().map(str::to_owned) else {
            continue;
        };
        let Some(version_text) = directory.strip_prefix('v') else {
            continue;
        };
        let Ok(version) = Version::parse(version_text) else {
            continue;
        };
        if version.to_string() != version_text
            || !version.pre.is_empty()
            || !version.build.is_empty()
        {
            continue;
        }
        let matches = exact.as_ref().is_some_and(|exact| exact == &version)
            || requirement
                .as_ref()
                .is_some_and(|requirement| requirement.matches(&version));
        if matches && selected.as_ref().is_none_or(|current| &version > current) {
            selected = Some(version);
        }
    }

    let version = selected.ok_or_else(|| {
        Error::new(
            "not_found",
            format!("no published binary {name:?} matches {selector:?}"),
        )
    })?;
    let version_root = checked_directory(
        &binary_root.join(format!("v{version}")),
        "published binary version",
    )?;
    let executable = version_root.join(name);
    let metadata = fs::symlink_metadata(&executable)
        .map_err(|error| Error::io("inspect published executable", &executable, error))?;
    if metadata.file_type().is_symlink() || !metadata.is_file() {
        return Err(Error::new(
            "invalid_publication",
            format!(
                "published executable is not a regular file: {}",
                executable.display()
            ),
        ));
    }
    Ok(Publication {
        version,
        executable,
    })
}

fn stable_version(value: &str) -> Result<Version> {
    let version = Version::parse(value).map_err(|error| {
        Error::new(
            "invalid_publication",
            format!("invalid binary version {value:?}: {error}"),
        )
    })?;
    if version.to_string() != value || !version.pre.is_empty() || !version.build.is_empty() {
        return Err(Error::new(
            "invalid_publication",
            format!("binary version is not canonical stable SemVer: {value:?}"),
        ));
    }
    Ok(version)
}

fn checked_root(path: &Path, create: bool) -> Result<PathBuf> {
    let absolute = if path.is_absolute() {
        path.to_path_buf()
    } else {
        std::env::current_dir()
            .map_err(|error| Error::io("read current directory", ".", error))?
            .join(path)
    };
    if create {
        fs::create_dir_all(&absolute)
            .map_err(|error| Error::io("create binary publication root", &absolute, error))?;
    }
    checked_directory(&absolute, "binary publication root")?;
    fs::canonicalize(&absolute)
        .map_err(|error| Error::io("canonicalize binary publication root", &absolute, error))
}

fn create_checked_directory(path: &Path, label: &str) -> Result<()> {
    fs::create_dir_all(path).map_err(|error| Error::io("create directory", path, error))?;
    checked_directory(path, label).map(|_| ())
}

fn checked_directory(path: &Path, label: &str) -> Result<PathBuf> {
    match fs::symlink_metadata(path) {
        Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_dir() => Err(Error::new(
            "invalid_publication",
            format!("{label} is not a regular directory: {}", path.display()),
        )),
        Ok(_) => Ok(path.to_path_buf()),
        Err(error) if error.kind() == io::ErrorKind::NotFound => Err(Error::new(
            "not_found",
            format!("{label} does not exist: {}", path.display()),
        )),
        Err(error) => Err(Error::io("inspect directory", path, error)),
    }
}

fn path_exists(path: &Path) -> Result<bool> {
    match fs::symlink_metadata(path) {
        Ok(_) => Ok(true),
        Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
        Err(error) => Err(Error::io("inspect publication path", path, error)),
    }
}

fn lock_file(path: &Path) -> Result<PublicationLock> {
    match fs::symlink_metadata(path) {
        Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_file() => {
            return Err(Error::new(
                "invalid_publication",
                format!("publication lock is not a regular file: {}", path.display()),
            ));
        }
        Ok(_) => {}
        Err(error) if error.kind() == io::ErrorKind::NotFound => {}
        Err(error) => return Err(Error::io("inspect publication lock", path, error)),
    }
    let file = OpenOptions::new()
        .create(true)
        .truncate(false)
        .read(true)
        .write(true)
        .open(path)
        .map_err(|error| Error::io("open publication lock", path, error))?;
    if !file
        .metadata()
        .map_err(|error| Error::io("inspect opened publication lock", path, error))?
        .is_file()
    {
        return Err(Error::new(
            "invalid_publication",
            "opened publication lock is not a regular file",
        ));
    }
    FsFile::lock(&file).map_err(|error| Error::io("lock binary publication", path, error))?;
    Ok(PublicationLock(file))
}

struct PublicationLock(FsFile);

impl Drop for PublicationLock {
    fn drop(&mut self) {
        let _ = FsFile::unlock(&self.0);
    }
}

fn sync_directory(path: &Path) -> Result<()> {
    FsFile::open(path)
        .and_then(|directory| directory.sync_all())
        .map_err(|error| Error::io("sync directory", path, error))
}

#[cfg(unix)]
fn set_executable(path: &Path) -> Result<()> {
    let mut permissions = fs::metadata(path)
        .map_err(|error| Error::io("inspect published executable", path, error))?
        .permissions();
    permissions.set_mode(0o500);
    fs::set_permissions(path, permissions)
        .map_err(|error| Error::io("mark published executable", path, error))
}

#[cfg(not(unix))]
fn set_executable(_path: &Path) -> Result<()> {
    Err(Error::new(
        "unsupported_host",
        "published executables require a Unix host",
    ))
}

fn unique_id() -> String {
    let nanos = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap_or_default()
        .as_nanos();
    let counter = UNIQUE_COUNTER.fetch_add(1, Ordering::Relaxed);
    format!("{:x}-{nanos:x}-{counter:x}", std::process::id())
}

#[cfg(test)]
mod tests {
    use std::fs;
    use std::path::{Path, PathBuf};
    use std::sync::atomic::{AtomicU64, Ordering};

    use super::{publish, resolve};

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

    struct TestRoot(PathBuf);

    impl TestRoot {
        fn new() -> Self {
            let counter = TEST_COUNTER.fetch_add(1, Ordering::Relaxed);
            let path = std::env::temp_dir().join(format!(
                "kcode-rust-bin-publications-{}-{counter}",
                std::process::id()
            ));
            fs::create_dir(&path).unwrap();
            Self(path)
        }

        fn path(&self) -> &Path {
            &self.0
        }
    }

    impl Drop for TestRoot {
        fn drop(&mut self) {
            let _ = fs::remove_dir_all(&self.0);
        }
    }

    #[test]
    fn publication_is_immutable_and_cargo_requirements_select_the_highest_match() {
        let root = TestRoot::new();
        publish(root.path(), "demo", "1.2.3", b"one").unwrap();
        publish(root.path(), "demo", "1.9.0", b"two").unwrap();
        publish(root.path(), "demo", "2.0.0", b"three").unwrap();

        let exact = resolve(root.path(), "demo", "v1.2.3").unwrap();
        assert_eq!(exact.version.to_string(), "1.2.3");
        assert_eq!(fs::read(exact.executable).unwrap(), b"one");

        let compatible = resolve(root.path(), "demo", "1.2").unwrap();
        assert_eq!(compatible.version.to_string(), "1.9.0");
        assert_eq!(fs::read(compatible.executable).unwrap(), b"two");

        let duplicate = publish(root.path(), "demo", "1.2.3", b"different").unwrap_err();
        assert!(duplicate.to_string().starts_with("already_published:"));
    }
}