mobius-gateway 0.15.8

Headless authenticated gateway for möbius frontends
Documentation
use std::fs;
use std::io::Write as _;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt as _;
use std::path::Path;

use crate::Result;

pub(crate) fn publish(path: &Path, contents: &[u8], create_new: bool) -> Result<()> {
    let parent = path
        .parent()
        .ok_or_else(|| crate::Error::Config("publication path has no parent".into()))?;
    let parent_file = fs::File::open(parent)?;
    let mut file = tempfile::NamedTempFile::new_in(parent)?;
    #[cfg(unix)]
    file.as_file()
        .set_permissions(fs::Permissions::from_mode(0o600))?;
    file.write_all(contents)?;
    file.as_file().sync_all()?;
    if create_new {
        file.persist_noclobber(path).map_err(|error| error.error)?;
    } else {
        file.persist(path).map_err(|error| error.error)?;
    }
    parent_file.sync_all()?;
    Ok(())
}

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

    #[test]
    fn publish_replaces_existing_file() {
        let directory = tempfile::tempdir().expect("publication directory");
        let path = directory.path().join("state");
        fs::write(&path, b"old").expect("old state");

        publish(&path, b"new", false).expect("replace state");

        assert_eq!(fs::read(path).expect("read state"), b"new");
    }

    #[test]
    fn publish_create_new_rejects_existing_file() {
        let directory = tempfile::tempdir().expect("publication directory");
        let path = directory.path().join("state");
        fs::write(&path, b"old").expect("old state");

        assert!(publish(&path, b"new", true).is_err());
        assert_eq!(fs::read(path).expect("read state"), b"old");
    }

    #[test]
    fn publish_propagates_parent_errors() {
        let directory = tempfile::tempdir().expect("publication directory");
        let path = directory.path().join("missing").join("state");

        assert!(publish(&path, b"state", false).is_err());
    }
}