]> git.proxmox.com Git - rustc.git/blame - src/bootstrap/format.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / src / bootstrap / format.rs
CommitLineData
dfeec247
XL
1//! Runs rustfmt on the repository.
2
3use crate::Build;
74b04a01 4use build_helper::{output, t};
dfeec247
XL
5use ignore::WalkBuilder;
6use std::path::Path;
ba9703b0 7use std::process::{Command, Stdio};
dfeec247
XL
8
9fn rustfmt(src: &Path, rustfmt: &Path, path: &Path, check: bool) {
10 let mut cmd = Command::new(&rustfmt);
11 // avoid the submodule config paths from coming into play,
12 // we only allow a single global config for the workspace for now
13 cmd.arg("--config-path").arg(&src.canonicalize().unwrap());
14 cmd.arg("--edition").arg("2018");
15 cmd.arg("--unstable-features");
16 cmd.arg("--skip-children");
17 if check {
18 cmd.arg("--check");
19 }
20 cmd.arg(&path);
21 let cmd_debug = format!("{:?}", cmd);
22 let status = cmd.status().expect("executing rustfmt");
23 if !status.success() {
24 eprintln!(
25 "Running `{}` failed.\nIf you're running `tidy`, \
f9f354fc 26 try again with `--bless`. Or, if you just want to format \
dfeec247
XL
27 code, run `./x.py fmt` instead.",
28 cmd_debug,
29 );
30 std::process::exit(1);
31 }
32}
33
34#[derive(serde::Deserialize)]
35struct RustfmtConfig {
36 ignore: Vec<String>,
37}
38
39pub fn format(build: &Build, check: bool) {
ba9703b0
XL
40 if build.config.dry_run {
41 return;
42 }
dfeec247
XL
43 let mut builder = ignore::types::TypesBuilder::new();
44 builder.add_defaults();
45 builder.select("rust");
46 let matcher = builder.build().unwrap();
47 let rustfmt_config = build.src.join("rustfmt.toml");
48 if !rustfmt_config.exists() {
49 eprintln!("Not running formatting checks; rustfmt.toml does not exist.");
50 eprintln!("This may happen in distributed tarballs.");
51 return;
52 }
53 let rustfmt_config = t!(std::fs::read_to_string(&rustfmt_config));
54 let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config));
55 let mut ignore_fmt = ignore::overrides::OverrideBuilder::new(&build.src);
56 for ignore in rustfmt_config.ignore {
57 ignore_fmt.add(&format!("!{}", ignore)).expect(&ignore);
58 }
ba9703b0
XL
59 let git_available = match Command::new("git")
60 .arg("--version")
61 .stdout(Stdio::null())
62 .stderr(Stdio::null())
63 .status()
64 {
65 Ok(status) => status.success(),
66 Err(_) => false,
67 };
68 if git_available {
69 let in_working_tree = match Command::new("git")
70 .arg("rev-parse")
71 .arg("--is-inside-work-tree")
72 .stdout(Stdio::null())
73 .stderr(Stdio::null())
74 .status()
75 {
76 Ok(status) => status.success(),
77 Err(_) => false,
78 };
79 if in_working_tree {
80 let untracked_paths_output = output(
81 Command::new("git")
82 .arg("status")
83 .arg("--porcelain")
84 .arg("--untracked-files=normal"),
85 );
86 let untracked_paths = untracked_paths_output
87 .lines()
88 .filter(|entry| entry.starts_with("??"))
89 .map(|entry| {
3dfed10e 90 entry.split(' ').nth(1).expect("every git status entry should list a path")
ba9703b0
XL
91 });
92 for untracked_path in untracked_paths {
93 eprintln!("skip untracked path {} during rustfmt invocations", untracked_path);
94 ignore_fmt.add(&format!("!{}", untracked_path)).expect(&untracked_path);
95 }
96 } else {
97 eprintln!("Not in git tree. Skipping git-aware format checks");
98 }
99 } else {
100 eprintln!("Could not find usable git. Skipping git-aware format checks");
74b04a01 101 }
dfeec247
XL
102 let ignore_fmt = ignore_fmt.build().unwrap();
103
104 let rustfmt_path = build.config.initial_rustfmt.as_ref().unwrap_or_else(|| {
105 eprintln!("./x.py fmt is not supported on this channel");
106 std::process::exit(1);
107 });
1b1a35ee
XL
108 let src = &build.src;
109 let walker = WalkBuilder::new(src).types(matcher).overrides(ignore_fmt).build_parallel();
dfeec247 110 walker.run(|| {
dfeec247
XL
111 Box::new(move |entry| {
112 let entry = t!(entry);
113 if entry.file_type().map_or(false, |t| t.is_file()) {
1b1a35ee 114 rustfmt(src, &rustfmt_path, &entry.path(), check);
dfeec247
XL
115 }
116 ignore::WalkState::Continue
117 })
118 });
119}