1 use std::env;
2 use std::fs;
3 use std::path::{Path, PathBuf};
4
5 /// The expected extension of rustfmt manifest files generated by `rustfmt_aspect`.
6 pub const RUSTFMT_MANIFEST_EXTENSION: &str = "rustfmt";
7
8 /// A struct containing details used for executing rustfmt.
9 #[derive(Debug)]
10 pub struct RustfmtConfig {
11 /// The rustfmt binary from the currently active toolchain
12 pub rustfmt: PathBuf,
13
14 /// The rustfmt config file containing rustfmt settings.
15 /// https://rust-lang.github.io/rustfmt/
16 pub config: PathBuf,
17 }
18
19 /// Parse command line arguments and environment variables to
20 /// produce config data for running rustfmt.
parse_rustfmt_config() -> RustfmtConfig21 pub fn parse_rustfmt_config() -> RustfmtConfig {
22 let runfiles = runfiles::Runfiles::create().unwrap();
23
24 let rustfmt = runfiles::rlocation!(runfiles, env!("RUSTFMT"));
25 if !rustfmt.exists() {
26 panic!("rustfmt does not exist at: {}", rustfmt.display());
27 }
28
29 let config = runfiles::rlocation!(runfiles, env!("RUSTFMT_CONFIG"));
30 if !config.exists() {
31 panic!(
32 "rustfmt config file does not exist at: {}",
33 config.display()
34 );
35 }
36
37 RustfmtConfig { rustfmt, config }
38 }
39
40 /// A struct of target specific information for use in running `rustfmt`.
41 #[derive(Debug)]
42 pub struct RustfmtManifest {
43 /// The Rust edition of the Bazel target
44 pub edition: String,
45
46 /// A list of all (non-generated) source files for formatting.
47 pub sources: Vec<PathBuf>,
48 }
49
50 /// Parse rustfmt flags from a manifest generated by builds using `rustfmt_aspect`.
parse_rustfmt_manifest(manifest: &Path) -> RustfmtManifest51 pub fn parse_rustfmt_manifest(manifest: &Path) -> RustfmtManifest {
52 let content = fs::read_to_string(manifest)
53 .unwrap_or_else(|_| panic!("Failed to read rustfmt manifest: {}", manifest.display()));
54
55 let mut lines: Vec<String> = content
56 .split('\n')
57 .filter(|s| !s.is_empty())
58 .map(|s| s.to_owned())
59 .collect();
60
61 let edition = lines
62 .pop()
63 .expect("There should always be at least 1 line in the manifest");
64 edition
65 .parse::<i32>()
66 .expect("The edition should be a numeric value. eg `2018`.");
67
68 let runfiles = runfiles::Runfiles::create().unwrap();
69
70 RustfmtManifest {
71 edition,
72 sources: lines
73 .into_iter()
74 .map(|src| runfiles::rlocation!(runfiles, src))
75 .collect(),
76 }
77 }
78
79 #[cfg(target_family = "windows")]
80 const PATH_ENV_SEP: &str = ";";
81
82 #[cfg(target_family = "unix")]
83 const PATH_ENV_SEP: &str = ":";
84
85 /// Parse the runfiles of the current executable for manifests generated
86 /// by the `rustfmt_aspect` aspect.
find_manifests() -> Vec<PathBuf>87 pub fn find_manifests() -> Vec<PathBuf> {
88 let runfiles = runfiles::Runfiles::create().unwrap();
89
90 std::env::var("RUSTFMT_MANIFESTS")
91 .map(|var| {
92 var.split(PATH_ENV_SEP)
93 .map(|path| runfiles::rlocation!(runfiles, path))
94 .collect()
95 })
96 .unwrap_or_default()
97 }
98