sailfish_compiler/
util.rs

1use std::fs;
2use std::io::{self, Write};
3use std::path::{Path, PathBuf};
4use std::process::{Command, Stdio};
5
6pub fn read_to_string(path: &Path) -> io::Result<String> {
7    let mut content = std::fs::read_to_string(path)?;
8
9    // strip break line at file end
10    if content.ends_with('\n') {
11        content.truncate(content.len() - 1);
12        if content.ends_with('\r') {
13            content.truncate(content.len() - 1);
14        }
15    }
16
17    Ok(content)
18}
19
20fn find_rustfmt() -> io::Result<Option<PathBuf>> {
21    let mut toolchain_dir = home::rustup_home()?;
22    toolchain_dir.push("toolchains");
23    for e in fs::read_dir(toolchain_dir)? {
24        let mut path = e?.path();
25        path.push("bin");
26        path.push("rustfmt");
27        if path.exists() {
28            return Ok(Some(path));
29        }
30    }
31
32    Ok(None)
33}
34
35/// Format block expression using `rustfmt` command
36pub fn rustfmt_block(source: &str) -> io::Result<String> {
37    let rustfmt = match find_rustfmt()? {
38        Some(p) => p,
39        None => {
40            return Err(io::Error::new(
41                io::ErrorKind::NotFound,
42                "rustfmt command not found",
43            ))
44        }
45    };
46
47    let mut new_source = String::with_capacity(source.len() + 11);
48    new_source.push_str("fn render()");
49    new_source.push_str(source);
50
51    let mut child = Command::new(rustfmt)
52        .args(["--emit", "stdout", "--color", "never", "--quiet"])
53        .stdin(Stdio::piped())
54        .stdout(Stdio::piped())
55        .stderr(Stdio::null())
56        .spawn()?;
57
58    let stdin = child
59        .stdin
60        .as_mut()
61        .ok_or_else(|| io::Error::from(io::ErrorKind::BrokenPipe))?;
62    stdin.write_all(new_source.as_bytes())?;
63
64    let output = child.wait_with_output()?;
65
66    if output.status.success() {
67        let mut s =
68            String::from_utf8(output.stdout).expect("rustfmt output is non-UTF-8!");
69        let brace_offset = s.find('{').unwrap();
70        s.replace_range(..brace_offset, "");
71        Ok(s)
72    } else {
73        Err(io::Error::new(
74            io::ErrorKind::Other,
75            "rustfmt command failed",
76        ))
77    }
78}
79
80#[cfg(feature = "procmacro")]
81pub fn filetime(input: &Path) -> filetime::FileTime {
82    use filetime::FileTime;
83    fs::metadata(input)
84        .and_then(|metadata| metadata.modified())
85        .map_or(FileTime::zero(), FileTime::from_system_time)
86}