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(format!(
25 "{}/{}",
26 runfiles.current_repository(),
27 env!("RUSTFMT")
28 ));
29 if !rustfmt.exists() {
30 panic!("rustfmt does not exist at: {}", rustfmt.display());
31 }
32
33 let config = runfiles.rlocation(format!(
34 "{}/{}",
35 runfiles.current_repository(),
36 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)]
50 pub 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`.
parse_rustfmt_manifest(manifest: &Path) -> RustfmtManifest59 pub 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')
65 .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()
82 .map(|src| runfiles.rlocation(format!("{}/{}", runfiles.current_repository(), src)))
83 .collect(),
84 }
85 }
86
87 #[cfg(target_family = "windows")]
88 const PATH_ENV_SEP: &str = ";";
89
90 #[cfg(target_family = "unix")]
91 const PATH_ENV_SEP: &str = ":";
92
93 /// Parse the runfiles of the current executable for manifests generated
94 /// by the `rustfmt_aspect` aspect.
find_manifests() -> Vec<PathBuf>95 pub 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)
101 .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 })
109 .collect()
110 })
111 .unwrap_or_default()
112 }
113