blob: 9658a76e6438a494d3c37fa7d207cb371a3c6169 [file] [log] [blame]
Brian Silverman5f6f2762022-08-13 19:30:05 -07001use 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/// A struct containing details used for executing rustfmt.
9#[derive(Debug)]
10pub 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.
21pub fn parse_rustfmt_config() -> RustfmtConfig {
22 let runfiles = runfiles::Runfiles::create().unwrap();
23
Adam Snaider1c095c92023-07-08 02:09:58 -040024 let rustfmt = runfiles.rlocation(format!(
25 "{}/{}",
26 runfiles.current_repository(),
27 env!("RUSTFMT")
28 ));
Brian Silverman5f6f2762022-08-13 19:30:05 -070029 if !rustfmt.exists() {
30 panic!("rustfmt does not exist at: {}", rustfmt.display());
31 }
32
Adam Snaider1c095c92023-07-08 02:09:58 -040033 let config = runfiles.rlocation(format!(
34 "{}/{}",
35 runfiles.current_repository(),
Brian Silverman5f6f2762022-08-13 19:30:05 -070036 env!("RUSTFMT_CONFIG")
37 ));
38 if !config.exists() {
39 panic!(
40 "rustfmt config file does not exist at: {}",
41 config.display()
42 );
43 }
44
45 RustfmtConfig { rustfmt, config }
46}
47
48/// A struct of target specific information for use in running `rustfmt`.
49#[derive(Debug)]
50pub struct RustfmtManifest {
51 /// The Rust edition of the Bazel target
52 pub edition: String,
53
54 /// A list of all (non-generated) source files for formatting.
55 pub sources: Vec<PathBuf>,
56}
57
58/// Parse rustfmt flags from a manifest generated by builds using `rustfmt_aspect`.
59pub fn parse_rustfmt_manifest(manifest: &Path) -> RustfmtManifest {
60 let content = fs::read_to_string(manifest)
61 .unwrap_or_else(|_| panic!("Failed to read rustfmt manifest: {}", manifest.display()));
62
63 let mut lines: Vec<String> = content
64 .split('\n')
Brian Silverman5f6f2762022-08-13 19:30:05 -070065 .filter(|s| !s.is_empty())
66 .map(|s| s.to_owned())
67 .collect();
68
69 let edition = lines
70 .pop()
71 .expect("There should always be at least 1 line in the manifest");
72 edition
73 .parse::<i32>()
74 .expect("The edition should be a numeric value. eg `2018`.");
75
76 let runfiles = runfiles::Runfiles::create().unwrap();
77
78 RustfmtManifest {
79 edition,
80 sources: lines
81 .into_iter()
Adam Snaider1c095c92023-07-08 02:09:58 -040082 .map(|src| runfiles.rlocation(format!("{}/{}", runfiles.current_repository(), src)))
Brian Silverman5f6f2762022-08-13 19:30:05 -070083 .collect(),
84 }
85}
86
87#[cfg(target_family = "windows")]
88const PATH_ENV_SEP: &str = ";";
89
90#[cfg(target_family = "unix")]
91const PATH_ENV_SEP: &str = ":";
92
93/// Parse the runfiles of the current executable for manifests generated
94/// by the `rustfmt_aspect` aspect.
95pub fn find_manifests() -> Vec<PathBuf> {
96 let runfiles = runfiles::Runfiles::create().unwrap();
97
98 std::env::var("RUSTFMT_MANIFESTS")
99 .map(|var| {
100 var.split(PATH_ENV_SEP)
Adam Snaider1c095c92023-07-08 02:09:58 -0400101 .filter_map(|path| match path.is_empty() {
102 true => None,
103 false => Some(runfiles.rlocation(format!(
104 "{}/{}",
105 runfiles.current_repository(),
106 path
107 ))),
108 })
Brian Silverman5f6f2762022-08-13 19:30:05 -0700109 .collect()
110 })
111 .unwrap_or_default()
112}