xref: /aosp_15_r20/external/bazelbuild-rules_rust/tools/rustfmt/src/lib.rs (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
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