1use std::io::Write as _;
4
5use crate::{
6 error::{Error, Operation, Result},
7 file,
8 path::Path,
9};
10
11pub fn create(path: &Path, contents: impl AsRef<[u8]>) -> Result<()> {
24 let mut executable = file::create_new(path)?;
25
26 executable
27 .write_all(contents.as_ref())
28 .map_err(|source| Error::new(Operation::WriteFile, path, source))?;
29 executable
30 .flush()
31 .map_err(|source| Error::new(Operation::WriteFile, path, source))?;
32 executable.make_executable()?;
33
34 executable.sync()
35}
36
37#[cfg(test)]
38mod tests {
39 use googletest::prelude::*;
40
41 use super::create;
42 use crate::{file, temporary::Directory};
43
44 #[gtest]
45 fn create_persists_exact_bytes_without_replacing_existing_file() -> Result<()> {
46 let directory = Directory::new().or_fail()?;
47 let path = directory.path().join("fixture");
48
49 create(&path, b"first").or_fail()?;
50
51 verify_that!(file::read_bytes(&path).or_fail()?, eq(b"first"))?;
52 verify_true!(create(&path, b"second").is_err())?;
53
54 verify_that!(file::read_bytes(&path).or_fail()?, eq(b"first"))
55 }
56
57 #[cfg(unix)]
58 #[gtest]
59 fn create_marks_unix_script_executable() -> Result<()> {
60 let directory = Directory::new().or_fail()?;
61 let path = directory.path().join("fixture");
62
63 create(&path, b"#!/bin/sh\nprintf executable\n").or_fail()?;
64 let output = std::process::Command::new(&path).output().or_fail()?;
65
66 verify_true!(output.status.success())?;
67
68 verify_that!(output.stdout, eq(b"executable"))
69 }
70}