Skip to content

Commit 46c9cfc

Browse files
committed
Merge remote-tracking branch 'upstream/master' into subtree-push-nightly-2024-12-02
2 parents 232528a + 9f8fcc2 commit 46c9cfc

File tree

149 files changed

+1313
-466
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

149 files changed

+1313
-466
lines changed

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
use std::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64};
4040
```
4141
[style guide's version sorting algorithm]: https://doc.rust-lang.org/nightly/style-guide/#sorting
42-
- When parsing rustfmt configurations fails, rustfmt will now include the path to the toml file in the erorr message [#6302](https://github.com/rust-lang/rustfmt/issues/6302)
42+
- When parsing rustfmt configurations fails, rustfmt will now include the path to the toml file in the error message [#6302](https://github.com/rust-lang/rustfmt/issues/6302)
4343

4444
### Added
4545
- rustfmt now formats trailing where clauses in type aliases [#5887](https://github.com/rust-lang/rustfmt/pull/5887)
@@ -133,7 +133,7 @@
133133
### Changed
134134

135135
- `hide_parse_errors` has been soft deprecated and it's been renamed to `show_parse_errors` [#5961](https://github.com/rust-lang/rustfmt/pull/5961).
136-
- The diff output produced by `rustfmt --check` is more compatable with editors that support navigating directly to line numbers [#5971](https://github.com/rust-lang/rustfmt/pull/5971)
136+
- The diff output produced by `rustfmt --check` is more compatible with editors that support navigating directly to line numbers [#5971](https://github.com/rust-lang/rustfmt/pull/5971)
137137
- When using `version=Two`, the `trace!` macro from the [log crate] is now formatted similarly to `debug!`, `info!`, `warn!`, and `error!` [#5987](https://github.com/rust-lang/rustfmt/issues/5987).
138138

139139
[log crate]: https://crates.io/crates/log

Configurations.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3062,7 +3062,9 @@ fn main() {
30623062

30633063
## `version`
30643064

3065-
This option is deprecated and has been replaced by [`style_edition`](#style_edition)
3065+
This option is deprecated and has been replaced by [`style_edition`](#style_edition).
3066+
`version = "One"` is equivalent to `style_edition = "(2015|2018|2021)"` and
3067+
`version = "Two"` is equivalent to `style_edition = "2024"`
30663068

30673069
- **Default value**: `One`
30683070
- **Possible values**: `One`, `Two`
@@ -3112,7 +3114,7 @@ Break comments to fit on the line
31123114

31133115
Note that no wrapping will happen if:
31143116
1. The comment is the start of a markdown header doc comment
3115-
2. An URL was found in the comment
3117+
2. A URL was found in the comment
31163118

31173119
- **Default value**: `false`
31183120
- **Possible values**: `true`, `false`

check_diff/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,4 @@ edition = "2021"
99
clap = { version = "4.4.2", features = ["derive"] }
1010
tracing = "0.1.37"
1111
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
12-
[dev-dependencies]
1312
tempfile = "3"

check_diff/src/lib.rs

Lines changed: 215 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,49 @@
11
use std::env;
22
use std::io;
3-
use std::path::Path;
3+
use std::path::{Path, PathBuf};
44
use std::process::Command;
5+
use std::str::Utf8Error;
56
use tracing::info;
67

8+
pub enum CheckDiffError {
9+
/// Git related errors
10+
FailedGit(GitError),
11+
/// Error for generic commands
12+
FailedCommand(&'static str),
13+
/// UTF8 related errors
14+
FailedUtf8(Utf8Error),
15+
/// Error for building rustfmt from source
16+
FailedSourceBuild(&'static str),
17+
/// Error when obtaining binary version
18+
FailedBinaryVersioning(PathBuf),
19+
/// Error when obtaining cargo version
20+
FailedCargoVersion(&'static str),
21+
IO(std::io::Error),
22+
}
23+
24+
impl From<io::Error> for CheckDiffError {
25+
fn from(error: io::Error) -> Self {
26+
CheckDiffError::IO(error)
27+
}
28+
}
29+
30+
impl From<GitError> for CheckDiffError {
31+
fn from(error: GitError) -> Self {
32+
CheckDiffError::FailedGit(error)
33+
}
34+
}
35+
36+
impl From<Utf8Error> for CheckDiffError {
37+
fn from(error: Utf8Error) -> Self {
38+
CheckDiffError::FailedUtf8(error)
39+
}
40+
}
41+
742
pub enum GitError {
843
FailedClone { stdout: Vec<u8>, stderr: Vec<u8> },
44+
FailedRemoteAdd { stdout: Vec<u8>, stderr: Vec<u8> },
45+
FailedFetch { stdout: Vec<u8>, stderr: Vec<u8> },
46+
FailedSwitch { stdout: Vec<u8>, stderr: Vec<u8> },
947
IO(std::io::Error),
1048
}
1149

@@ -15,6 +53,35 @@ impl From<io::Error> for GitError {
1553
}
1654
}
1755

56+
// will be used in future PRs, just added to make the compiler happy
57+
#[allow(dead_code)]
58+
pub struct CheckDiffRunners {
59+
feature_runner: RustfmtRunner,
60+
src_runner: RustfmtRunner,
61+
}
62+
63+
pub struct RustfmtRunner {
64+
ld_library_path: String,
65+
binary_path: PathBuf,
66+
}
67+
68+
impl RustfmtRunner {
69+
fn get_binary_version(&self) -> Result<String, CheckDiffError> {
70+
let Ok(command) = Command::new(&self.binary_path)
71+
.env("LD_LIBRARY_PATH", &self.ld_library_path)
72+
.args(["--version"])
73+
.output()
74+
else {
75+
return Err(CheckDiffError::FailedBinaryVersioning(
76+
self.binary_path.clone(),
77+
));
78+
};
79+
80+
let binary_version = std::str::from_utf8(&command.stdout)?.trim();
81+
return Ok(binary_version.to_string());
82+
}
83+
}
84+
1885
/// Clone a git repository
1986
///
2087
/// Parameters:
@@ -47,6 +114,62 @@ pub fn clone_git_repo(url: &str, dest: &Path) -> Result<(), GitError> {
47114
return Ok(());
48115
}
49116

117+
pub fn git_remote_add(url: &str) -> Result<(), GitError> {
118+
let git_cmd = Command::new("git")
119+
.args(["remote", "add", "feature", url])
120+
.output()?;
121+
122+
// if the git command does not return successfully,
123+
// any command on the repo will fail. So fail fast.
124+
if !git_cmd.status.success() {
125+
let error = GitError::FailedRemoteAdd {
126+
stdout: git_cmd.stdout,
127+
stderr: git_cmd.stderr,
128+
};
129+
return Err(error);
130+
}
131+
132+
info!("Successfully added remote: {url}");
133+
return Ok(());
134+
}
135+
136+
pub fn git_fetch(branch_name: &str) -> Result<(), GitError> {
137+
let git_cmd = Command::new("git")
138+
.args(["fetch", "feature", branch_name])
139+
.output()?;
140+
141+
// if the git command does not return successfully,
142+
// any command on the repo will fail. So fail fast.
143+
if !git_cmd.status.success() {
144+
let error = GitError::FailedFetch {
145+
stdout: git_cmd.stdout,
146+
stderr: git_cmd.stderr,
147+
};
148+
return Err(error);
149+
}
150+
151+
info!("Successfully fetched: {branch_name}");
152+
return Ok(());
153+
}
154+
155+
pub fn git_switch(git_ref: &str, should_detach: bool) -> Result<(), GitError> {
156+
let detach_arg = if should_detach { "--detach" } else { "" };
157+
let args = ["switch", git_ref, detach_arg];
158+
let output = Command::new("git")
159+
.args(args.iter().filter(|arg| !arg.is_empty()))
160+
.output()?;
161+
if !output.status.success() {
162+
tracing::error!("Git switch failed: {output:?}");
163+
let error = GitError::FailedSwitch {
164+
stdout: output.stdout,
165+
stderr: output.stderr,
166+
};
167+
return Err(error);
168+
}
169+
info!("Successfully switched to {git_ref}");
170+
return Ok(());
171+
}
172+
50173
pub fn change_directory_to_path(dest: &Path) -> io::Result<()> {
51174
let dest_path = Path::new(&dest);
52175
env::set_current_dir(&dest_path)?;
@@ -56,3 +179,94 @@ pub fn change_directory_to_path(dest: &Path) -> io::Result<()> {
56179
);
57180
return Ok(());
58181
}
182+
183+
pub fn get_ld_library_path() -> Result<String, CheckDiffError> {
184+
let Ok(command) = Command::new("rustc").args(["--print", "sysroot"]).output() else {
185+
return Err(CheckDiffError::FailedCommand("Error getting sysroot"));
186+
};
187+
let sysroot = std::str::from_utf8(&command.stdout)?.trim_end();
188+
let ld_lib_path = format!("{}/lib", sysroot);
189+
return Ok(ld_lib_path);
190+
}
191+
192+
pub fn get_cargo_version() -> Result<String, CheckDiffError> {
193+
let Ok(command) = Command::new("cargo").args(["--version"]).output() else {
194+
return Err(CheckDiffError::FailedCargoVersion(
195+
"Failed to obtain cargo version",
196+
));
197+
};
198+
199+
let cargo_version = std::str::from_utf8(&command.stdout)?.trim_end();
200+
return Ok(cargo_version.to_string());
201+
}
202+
203+
/// Obtains the ld_lib path and then builds rustfmt from source
204+
/// If that operation succeeds, the source is then copied to the output path specified
205+
pub fn build_rustfmt_from_src(binary_path: PathBuf) -> Result<RustfmtRunner, CheckDiffError> {
206+
//Because we're building standalone binaries we need to set `LD_LIBRARY_PATH` so each
207+
// binary can find it's runtime dependencies.
208+
// See https://github.com/rust-lang/rustfmt/issues/5675
209+
// This will prepend the `LD_LIBRARY_PATH` for the master rustfmt binary
210+
let ld_lib_path = get_ld_library_path()?;
211+
212+
info!("Building rustfmt from source");
213+
let Ok(_) = Command::new("cargo")
214+
.args(["build", "-q", "--release", "--bin", "rustfmt"])
215+
.output()
216+
else {
217+
return Err(CheckDiffError::FailedSourceBuild(
218+
"Error building rustfmt from source",
219+
));
220+
};
221+
222+
std::fs::copy("target/release/rustfmt", &binary_path)?;
223+
224+
return Ok(RustfmtRunner {
225+
ld_library_path: ld_lib_path,
226+
binary_path,
227+
});
228+
}
229+
230+
// Compiles and produces two rustfmt binaries.
231+
// One for the current master, and another for the feature branch
232+
// Parameters:
233+
// dest: Directory where rustfmt will be cloned
234+
pub fn compile_rustfmt(
235+
dest: &Path,
236+
remote_repo_url: String,
237+
feature_branch: String,
238+
commit_hash: Option<String>,
239+
) -> Result<CheckDiffRunners, CheckDiffError> {
240+
const RUSTFMT_REPO: &str = "https://github.com/rust-lang/rustfmt.git";
241+
242+
clone_git_repo(RUSTFMT_REPO, dest)?;
243+
change_directory_to_path(dest)?;
244+
git_remote_add(remote_repo_url.as_str())?;
245+
git_fetch(feature_branch.as_str())?;
246+
247+
let cargo_version = get_cargo_version()?;
248+
info!("Compiling with {}", cargo_version);
249+
let src_runner = build_rustfmt_from_src(dest.join("src_rustfmt"))?;
250+
let should_detach = commit_hash.is_some();
251+
git_switch(
252+
commit_hash.unwrap_or(feature_branch).as_str(),
253+
should_detach,
254+
)?;
255+
256+
let feature_runner = build_rustfmt_from_src(dest.join("feature_rustfmt"))?;
257+
info!("RUSFMT_BIN {}", src_runner.get_binary_version()?);
258+
info!(
259+
"Runtime dependencies for (src) rustfmt -- LD_LIBRARY_PATH: {}",
260+
src_runner.ld_library_path
261+
);
262+
info!("FEATURE_BIN {}", feature_runner.get_binary_version()?);
263+
info!(
264+
"Runtime dependencies for (feature) rustfmt -- LD_LIBRARY_PATH: {}",
265+
feature_runner.ld_library_path
266+
);
267+
268+
return Ok(CheckDiffRunners {
269+
src_runner,
270+
feature_runner,
271+
});
272+
}

check_diff/src/main.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
use check_diff::compile_rustfmt;
12
use clap::Parser;
3+
use tempfile::Builder;
4+
use tracing::info;
25

36
/// Inputs for the check_diff script
47
#[derive(Parser)]
@@ -17,5 +20,16 @@ struct CliInputs {
1720
}
1821

1922
fn main() {
20-
let _args = CliInputs::parse();
23+
tracing_subscriber::fmt()
24+
.with_env_filter(tracing_subscriber::EnvFilter::from_env("CHECK_DIFF_LOG"))
25+
.init();
26+
let args = CliInputs::parse();
27+
let tmp_dir = Builder::new().tempdir_in("").unwrap();
28+
info!("Created tmp_dir {:?}", tmp_dir);
29+
let _ = compile_rustfmt(
30+
tmp_dir.path(),
31+
args.remote_repo_url,
32+
args.feature_branch,
33+
args.commit_hash,
34+
);
2135
}

src/attr.rs

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,22 @@ fn argument_shape(
5656
shape: Shape,
5757
context: &RewriteContext<'_>,
5858
) -> Option<Shape> {
59-
match context.config.indent_style() {
59+
let shape = match context.config.indent_style() {
6060
IndentStyle::Block => {
6161
if combine {
62-
shape.offset_left(left)
62+
shape.offset_left_opt(left)?
6363
} else {
64-
Some(
65-
shape
66-
.block_indent(context.config.tab_spaces())
67-
.with_max_width(context.config),
68-
)
64+
shape
65+
.block_indent(context.config.tab_spaces())
66+
.with_max_width(context.config)
6967
}
7068
}
7169
IndentStyle::Visual => shape
7270
.visual_indent(0)
73-
.shrink_left(left)
74-
.and_then(|s| s.sub_width(right)),
75-
}
71+
.shrink_left_opt(left)?
72+
.sub_width_opt(right)?,
73+
};
74+
Some(shape)
7675
}
7776

7877
fn format_derive(
@@ -127,8 +126,8 @@ fn format_derive(
127126
context,
128127
)?;
129128
let one_line_shape = shape
130-
.offset_left("[derive()]".len() + prefix.len())?
131-
.sub_width("()]".len())?;
129+
.offset_left_opt("[derive()]".len() + prefix.len())?
130+
.sub_width_opt("()]".len())?;
132131
let one_line_budget = one_line_shape.width;
133132

134133
let tactic = definitive_tactic(
@@ -295,7 +294,7 @@ impl Rewrite for ast::MetaItem {
295294
&path,
296295
list.iter(),
297296
// 1 = "]"
298-
shape.sub_width(1).max_width_error(shape.width, self.span)?,
297+
shape.sub_width(1, self.span)?,
299298
self.span,
300299
context.config.attr_fn_like_width(),
301300
Some(if has_trailing_comma {
@@ -308,9 +307,7 @@ impl Rewrite for ast::MetaItem {
308307
ast::MetaItemKind::NameValue(ref lit) => {
309308
let path = rewrite_path(context, PathContext::Type, &None, &self.path, shape)?;
310309
// 3 = ` = `
311-
let lit_shape = shape
312-
.shrink_left(path.len() + 3)
313-
.max_width_error(shape.width, self.span)?;
310+
let lit_shape = shape.shrink_left(path.len() + 3, self.span)?;
314311
// `rewrite_literal` returns `None` when `lit` exceeds max
315312
// width. Since a literal is basically unformattable unless it
316313
// is a string literal (and only if `format_strings` is set),
@@ -367,9 +364,7 @@ impl Rewrite for ast::Attribute {
367364
}
368365

369366
// 1 = `[`
370-
let shape = shape
371-
.offset_left(prefix.len() + 1)
372-
.max_width_error(shape.width, self.span)?;
367+
let shape = shape.offset_left(prefix.len() + 1, self.span)?;
373368
Ok(meta.rewrite_result(context, shape).map_or_else(
374369
|_| snippet.to_owned(),
375370
|rw| match &self.kind {

src/bin/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,7 @@ fn style_edition_from_style_edition_str(edition_str: &str) -> Result<StyleEditio
770770
"2018" => Ok(StyleEdition::Edition2018),
771771
"2021" => Ok(StyleEdition::Edition2021),
772772
"2024" => Ok(StyleEdition::Edition2024),
773+
"2027" => Ok(StyleEdition::Edition2027),
773774
_ => Err(format_err!("Invalid value for `--style-edition`")),
774775
}
775776
}

0 commit comments

Comments
 (0)