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