blob: ad2e86a5d66a7a5fecc500cf32af99a48572f75a [file] [log] [blame]
Brian Silvermancc09f182022-03-09 15:40:20 -08001use std::env;
2use std::fs;
3use std::path::{Path, PathBuf};
4
5/// The expected extension of rustfmt manifest files generated by `rustfmt_aspect`.
6pub const RUSTFMT_MANIFEST_EXTENSION: &str = "rustfmt";
7
8/// Generate an absolute path to a file without resolving symlinks
9fn absolutify_existing<T: AsRef<Path>>(path: &T) -> std::io::Result<PathBuf> {
10 let absolute_path = if path.as_ref().is_absolute() {
11 path.as_ref().to_owned()
12 } else {
13 std::env::current_dir()
14 .expect("Failed to get working directory")
15 .join(path)
16 };
17 std::fs::metadata(&absolute_path).map(|_| absolute_path)
18}
19
20/// A struct containing details used for executing rustfmt.
21#[derive(Debug)]
22pub struct RustfmtConfig {
23 /// The rustfmt binary from the currently active toolchain
24 pub rustfmt: PathBuf,
25
26 /// The rustfmt config file containing rustfmt settings.
27 /// https://rust-lang.github.io/rustfmt/
28 pub config: PathBuf,
29}
30
31/// Parse command line arguments and environment variables to
32/// produce config data for running rustfmt.
33pub fn parse_rustfmt_config() -> RustfmtConfig {
34 RustfmtConfig {
35 rustfmt: absolutify_existing(&env!("RUSTFMT")).expect("Unable to find rustfmt binary"),
36 config: absolutify_existing(&env!("RUSTFMT_CONFIG"))
37 .expect("Unable to find rustfmt config file"),
38 }
39}
40
41/// A struct of target specific information for use in running `rustfmt`.
42#[derive(Debug)]
43pub struct RustfmtManifest {
44 /// The Rust edition of the Bazel target
45 pub edition: String,
46
47 /// A list of all (non-generated) source files for formatting.
48 pub sources: Vec<String>,
49}
50
51/// Parse rustfmt flags from a manifest generated by builds using `rustfmt_aspect`.
52pub fn parse_rustfmt_manifest(manifest: &Path) -> RustfmtManifest {
53 let content = fs::read_to_string(manifest)
54 .unwrap_or_else(|_| panic!("Failed to read rustfmt manifest: {}", manifest.display()));
55
56 let mut lines: Vec<String> = content
57 .split('\n')
58 .into_iter()
59 .filter(|s| !s.is_empty())
60 .map(|s| s.to_owned())
61 .collect();
62
63 let edition = lines
64 .pop()
65 .expect("There should always be at least 1 line in the manifest");
66 edition
67 .parse::<i32>()
68 .expect("The edition should be a numeric value. eg `2018`.");
69
70 RustfmtManifest {
71 edition,
72 sources: lines,
73 }
74}