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