From 21b80feb1da2b3c12c800cf5b3f98c91865a17ce Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 10 Feb 2026 22:22:21 +0100 Subject: [PATCH 01/23] Remove the `Translator` type --- src/parse/session.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/parse/session.rs b/src/parse/session.rs index 2a5c8f77642..83a77e73cb7 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -5,7 +5,6 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::emitter::{DynEmitter, Emitter, SilentEmitter, stderr_destination}; -use rustc_errors::translation::Translator; use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel}; use rustc_session::parse::ParseSess as RawParseSess; use rustc_span::{ @@ -74,10 +73,6 @@ impl Emitter for SilentOnIgnoredFilesEmitter { } self.handle_non_ignoreable_error(diag); } - - fn translator(&self) -> &Translator { - self.emitter.translator() - } } impl From for ColorConfig { @@ -104,15 +99,13 @@ fn default_dcx( ColorConfig::Never }; - let translator = rustc_driver::default_translator(); - let emitter: Box = if show_parse_errors { Box::new( - AnnotateSnippetEmitter::new(stderr_destination(emit_color), translator) + AnnotateSnippetEmitter::new(stderr_destination(emit_color)) .sm(Some(source_map.clone())), ) } else { - Box::new(SilentEmitter { translator }) + Box::new(SilentEmitter) }; DiagCtxt::new(Box::new(SilentOnIgnoredFilesEmitter { has_non_ignorable_parser_errors: false, @@ -342,10 +335,6 @@ mod tests { fn emit_diagnostic(&mut self, _diag: DiagInner) { self.num_emitted_errors.fetch_add(1, Ordering::Release); } - - fn translator(&self) -> &Translator { - panic!("test emitter attempted to translate a diagnostic"); - } } fn build_diagnostic(level: DiagnosticLevel, span: Option) -> DiagInner { From 110da1a9da7367801ab01b47aee138ecce992760 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Thu, 26 Feb 2026 11:57:15 -0500 Subject: [PATCH 02/23] Merge commit 'cebab3e99259be82ff069e5ae89e91855d79e534' into rustfmt-subtree-update --- .github/workflows/check_diff.yml | 48 +- .github/workflows/integration.yml | 2 +- .github/workflows/linux.yml | 2 +- .github/workflows/mac.yml | 2 +- .github/workflows/rustdoc_check.yml | 2 +- .github/workflows/windows.yml | 2 +- CHANGELOG.md | 65 +- Cargo.lock | 388 +++++--- Cargo.toml | 19 +- Configurations.md | 210 ++++- Contributing.md | 14 +- Processes.md | 2 +- README.md | 29 +- Subtree sync procedure.md | 209 +++++ check_diff/Cargo.lock | 237 ++++- check_diff/Cargo.toml | 6 +- check_diff/src/lib.rs | 880 +++++++++++++++++- check_diff/src/main.rs | 104 ++- check_diff/tests/check_diff.rs | 97 ++ ci/check_diff.sh | 234 ----- docs/index.html | 57 +- rust-toolchain | 2 +- src/attr.rs | 33 +- src/bin/main.rs | 15 +- src/cargo-fmt/main.rs | 11 +- src/chains.rs | 93 +- src/closures.rs | 63 +- src/comment.rs | 5 +- src/config/config_type.rs | 6 +- src/config/file_lines.rs | 2 +- src/config/mod.rs | 449 ++++++++- src/config/options.rs | 74 +- src/config/style_edition.rs | 6 +- src/emitter/json.rs | 11 +- src/expr.rs | 383 ++++++-- src/format_report_formatter.rs | 86 +- src/imports.rs | 77 +- src/items.rs | 191 ++-- src/lists.rs | 26 +- src/macros.rs | 34 +- src/matches.rs | 57 +- src/missed_spans.rs | 3 +- src/modules.rs | 44 +- src/modules/visitor.rs | 64 +- src/overflow.rs | 6 +- src/pairs.rs | 37 +- src/parse/macros/cfg_match.rs | 80 ++ src/parse/macros/mod.rs | 2 +- src/patterns.rs | 19 +- src/reorder.rs | 46 +- src/rewrite.rs | 21 + src/shape.rs | 95 +- src/sort.rs | 11 +- src/stmt.rs | 8 +- src/syntux.rs | 4 - src/test/mod.rs | 41 + src/test/parser.rs | 4 +- src/types.rs | 55 +- src/vertical.rs | 2 +- src/visitor.rs | 77 +- tests/cargo-fmt/main.rs | 2 +- tests/rustfmt/main.rs | 65 +- tests/source/cfg_match/format_me_please_1.rs | 2 + tests/source/cfg_match/format_me_please_2.rs | 2 + tests/source/cfg_match/format_me_please_3.rs | 2 + tests/source/cfg_match/format_me_please_4.rs | 2 + tests/source/cfg_match/lib.rs | 16 + tests/source/cfg_match/lib2.rs | 3 + tests/source/closure-block-labels.rs | 192 ++++ .../float_literal_trailing_zero/always.rs | 45 + .../if-no-postfix.rs | 48 + .../float_literal_trailing_zero/never.rs | 49 + .../source/configs/match_arm_indent/attrs.rs | 24 + .../source/configs/match_arm_indent/guards.rs | 32 + .../configs/match_arm_indent/leading_pipes.rs | 18 + .../source/configs/match_arm_indent/nested.rs | 65 ++ .../configs/match_arm_indent/patterns.rs | 28 + .../configs/match_arm_indent/unindent.rs | 19 + tests/source/enum.rs | 6 +- tests/source/ergonomic_clones.rs | 73 ++ .../imports/imports_granularity_module.rs | 5 + tests/source/issue-1278.rs | 2 +- tests/source/issue-6202/long_pat.rs | 15 + tests/source/issue-6243.rs | 4 + tests/source/issue-6333.rs | 24 + tests/source/issue_5739.rs | 6 + tests/source/issue_6381_style_edition_2027.rs | 11 + tests/source/issue_6558.rs | 5 + tests/source/lazy_staic_before_2027.rs | 43 + tests/source/lazy_static.rs | 47 +- ...with_commnet.rs => no_arg_with_comment.rs} | 0 ...on_ascii_numerics_import_asciibetically.rs | 17 + .../non_ascii_numerics_import_versionsort.rs | 23 + tests/source/reorder_modules/A2/mod.rs | 1 + tests/source/reorder_modules/ABCD/mod.rs | 1 + tests/source/reorder_modules/ZYXW/mod.rs | 1 + tests/source/reorder_modules/ZYXW_/mod.rs | 1 + tests/source/reorder_modules/ZY_XW/mod.rs | 1 + tests/source/reorder_modules/Z_YXW/mod.rs | 1 + tests/source/reorder_modules/_ZYXW/mod.rs | 1 + tests/source/reorder_modules/_abcd/mod.rs | 1 + tests/source/reorder_modules/a1/mod.rs | 1 + tests/source/reorder_modules/abcd/mod.rs | 1 + .../disabled_style_edition_2024.rs | 47 + .../disabled_style_edition_2027.rs | 47 + .../enabled_style_edition_2015.rs | 47 + .../enabled_style_edition_2024.rs | 47 + .../enabled_style_edition_2027.rs | 47 + tests/source/reorder_modules/u128/mod.rs | 1 + tests/source/reorder_modules/u16/mod.rs | 1 + tests/source/reorder_modules/u256/mod.rs | 1 + tests/source/reorder_modules/u32/mod.rs | 1 + tests/source/reorder_modules/u64/mod.rs | 1 + tests/source/reorder_modules/u8/mod.rs | 1 + tests/source/reorder_modules/u_zzz/mod.rs | 1 + tests/source/reorder_modules/ua/mod.rs | 1 + tests/source/reorder_modules/usize/mod.rs | 1 + tests/source/reorder_modules/uz/mod.rs | 1 + tests/source/reorder_modules/v0/mod.rs | 1 + tests/source/reorder_modules/v00/mod.rs | 1 + tests/source/reorder_modules/v000/mod.rs | 1 + tests/source/reorder_modules/v001/mod.rs | 1 + tests/source/reorder_modules/v009/mod.rs | 1 + tests/source/reorder_modules/v00t/mod.rs | 1 + tests/source/reorder_modules/v01/mod.rs | 1 + tests/source/reorder_modules/v010/mod.rs | 1 + tests/source/reorder_modules/v09/mod.rs | 1 + tests/source/reorder_modules/v0s/mod.rs | 1 + tests/source/reorder_modules/v0u/mod.rs | 1 + tests/source/reorder_modules/v1/mod.rs | 1 + tests/source/reorder_modules/v10/mod.rs | 1 + tests/source/reorder_modules/v9/mod.rs | 1 + tests/source/reorder_modules/w005s09t/mod.rs | 1 + tests/source/reorder_modules/w5s009t/mod.rs | 1 + tests/source/reorder_modules/x64/mod.rs | 1 + tests/source/reorder_modules/x86/mod.rs | 1 + tests/source/reorder_modules/x86_128/mod.rs | 1 + tests/source/reorder_modules/x86_32/mod.rs | 1 + tests/source/reorder_modules/x86_64/mod.rs | 1 + tests/source/reorder_modules/x87/mod.rs | 1 + tests/source/reorder_modules/zyxw/mod.rs | 1 + ...-bodies-edition-2021-style-edition-2027.rs | 8 + ...-bodies-edition-2024-style-edition-2024.rs | 8 + .../source/trailing-semicolon/loop-bodies.rs | 36 + tests/source/unsafe-binders.rs | 2 + tests/source/unsafe-field.rs | 2 + .../use-identifier-order-mixed-edition.rs | 13 + tests/source/use-identifier-order.rs | 13 + tests/target/cfg_match/format_me_please_1.rs | 1 + tests/target/cfg_match/format_me_please_2.rs | 1 + tests/target/cfg_match/format_me_please_3.rs | 1 + tests/target/cfg_match/format_me_please_4.rs | 1 + tests/target/cfg_match/lib.rs | 16 + tests/target/cfg_match/lib2.rs | 3 + tests/target/closure-block-labels.rs | 204 ++++ .../float_literal_trailing_zero/always.rs | 49 + .../if-no-postfix.rs | 46 + .../float_literal_trailing_zero/never.rs | 45 + .../float_literal_trailing_zero/preserve.rs | 38 + .../target/configs/match_arm_indent/attrs.rs | 48 + .../target/configs/match_arm_indent/guards.rs | 31 + .../configs/match_arm_indent/leading_pipes.rs | 35 + .../target/configs/match_arm_indent/nested.rs | 79 ++ .../configs/match_arm_indent/noindent-tabs.rs | 23 + .../configs/match_arm_indent/noindent.rs | 21 + .../configs/match_arm_indent/patterns.rs | 28 + .../configs/match_arm_indent/unindent.rs | 19 + tests/target/enum.rs | 6 +- tests/target/ergonomic_clones.rs | 59 ++ .../imports/imports_granularity_module.rs | 7 + tests/target/issue-1278.rs | 2 +- tests/target/issue-5244/unwrapped.rs | 7 + tests/target/issue-5244/wrapped.rs | 8 + tests/target/issue-6202/long_pat.rs | 16 + tests/target/issue-6243.rs | 3 + tests/target/issue-6333-2024.rs | 24 + tests/target/issue-6333.rs | 24 + tests/target/issue-6411.rs | 21 + tests/target/issue_4573.rs | 2 +- tests/target/issue_4635.rs | 5 + tests/target/issue_5739.rs | 2 + tests/target/issue_6381_style_edition_2024.rs | 11 + tests/target/issue_6381_style_edition_2027.rs | 13 + tests/target/issue_6558.rs | 4 + tests/target/lazy_staic_before_2027.rs | 37 + tests/target/lazy_static.rs | 51 +- tests/target/multiple.rs | 6 +- ...with_commnet.rs => no_arg_with_comment.rs} | 0 ...on_ascii_numerics_import_asciibetically.rs | 17 + .../non_ascii_numerics_import_versionsort.rs | 23 + tests/target/reorder_modules/A2/mod.rs | 1 + tests/target/reorder_modules/ABCD/mod.rs | 1 + tests/target/reorder_modules/ZYXW/mod.rs | 1 + tests/target/reorder_modules/ZYXW_/mod.rs | 1 + tests/target/reorder_modules/ZY_XW/mod.rs | 1 + tests/target/reorder_modules/Z_YXW/mod.rs | 1 + tests/target/reorder_modules/_ZYXW/mod.rs | 1 + tests/target/reorder_modules/_abcd/mod.rs | 1 + tests/target/reorder_modules/a1/mod.rs | 1 + tests/target/reorder_modules/abcd/mod.rs | 1 + .../disabled_style_edition_2024.rs | 47 + .../disabled_style_edition_2027.rs | 47 + .../enabled_style_edition_2015.rs | 47 + .../enabled_style_edition_2024.rs | 47 + .../enabled_style_edition_2027.rs | 47 + tests/target/reorder_modules/u128/mod.rs | 1 + tests/target/reorder_modules/u16/mod.rs | 1 + tests/target/reorder_modules/u256/mod.rs | 1 + tests/target/reorder_modules/u32/mod.rs | 1 + tests/target/reorder_modules/u64/mod.rs | 1 + tests/target/reorder_modules/u8/mod.rs | 1 + tests/target/reorder_modules/u_zzz/mod.rs | 1 + tests/target/reorder_modules/ua/mod.rs | 1 + tests/target/reorder_modules/usize/mod.rs | 1 + tests/target/reorder_modules/uz/mod.rs | 1 + tests/target/reorder_modules/v0/mod.rs | 1 + tests/target/reorder_modules/v00/mod.rs | 1 + tests/target/reorder_modules/v000/mod.rs | 1 + tests/target/reorder_modules/v001/mod.rs | 1 + tests/target/reorder_modules/v009/mod.rs | 1 + tests/target/reorder_modules/v00t/mod.rs | 1 + tests/target/reorder_modules/v01/mod.rs | 1 + tests/target/reorder_modules/v010/mod.rs | 1 + tests/target/reorder_modules/v09/mod.rs | 1 + tests/target/reorder_modules/v0s/mod.rs | 1 + tests/target/reorder_modules/v0u/mod.rs | 1 + tests/target/reorder_modules/v1/mod.rs | 1 + tests/target/reorder_modules/v10/mod.rs | 1 + tests/target/reorder_modules/v9/mod.rs | 1 + tests/target/reorder_modules/w005s09t/mod.rs | 1 + tests/target/reorder_modules/w5s009t/mod.rs | 1 + tests/target/reorder_modules/x64/mod.rs | 1 + tests/target/reorder_modules/x86/mod.rs | 1 + tests/target/reorder_modules/x86_128/mod.rs | 1 + tests/target/reorder_modules/x86_32/mod.rs | 1 + tests/target/reorder_modules/x86_64/mod.rs | 1 + tests/target/reorder_modules/x87/mod.rs | 1 + tests/target/reorder_modules/zyxw/mod.rs | 1 + ...-bodies-edition-2021-style-edition-2027.rs | 8 + ...-bodies-edition-2024-style-edition-2024.rs | 8 + .../target/trailing-semicolon/loop-bodies.rs | 36 + tests/target/unsafe-binders.rs | 2 + tests/target/unsafe-field.rs | 2 + .../use-identifier-order-mixed-edition.rs | 11 + tests/target/use-identifier-order.rs | 11 + triagebot.toml | 81 +- 246 files changed, 6481 insertions(+), 1100 deletions(-) create mode 100644 Subtree sync procedure.md create mode 100644 check_diff/tests/check_diff.rs delete mode 100755 ci/check_diff.sh create mode 100644 src/parse/macros/cfg_match.rs delete mode 100644 src/syntux.rs create mode 100644 tests/source/cfg_match/format_me_please_1.rs create mode 100644 tests/source/cfg_match/format_me_please_2.rs create mode 100644 tests/source/cfg_match/format_me_please_3.rs create mode 100644 tests/source/cfg_match/format_me_please_4.rs create mode 100644 tests/source/cfg_match/lib.rs create mode 100644 tests/source/cfg_match/lib2.rs create mode 100644 tests/source/closure-block-labels.rs create mode 100644 tests/source/configs/float_literal_trailing_zero/always.rs create mode 100644 tests/source/configs/float_literal_trailing_zero/if-no-postfix.rs create mode 100644 tests/source/configs/float_literal_trailing_zero/never.rs create mode 100644 tests/source/configs/match_arm_indent/attrs.rs create mode 100644 tests/source/configs/match_arm_indent/guards.rs create mode 100644 tests/source/configs/match_arm_indent/leading_pipes.rs create mode 100644 tests/source/configs/match_arm_indent/nested.rs create mode 100644 tests/source/configs/match_arm_indent/patterns.rs create mode 100644 tests/source/configs/match_arm_indent/unindent.rs create mode 100644 tests/source/ergonomic_clones.rs create mode 100644 tests/source/issue-6202/long_pat.rs create mode 100644 tests/source/issue-6243.rs create mode 100644 tests/source/issue-6333.rs create mode 100644 tests/source/issue_5739.rs create mode 100644 tests/source/issue_6381_style_edition_2027.rs create mode 100644 tests/source/issue_6558.rs create mode 100644 tests/source/lazy_staic_before_2027.rs rename tests/source/{no_arg_with_commnet.rs => no_arg_with_comment.rs} (100%) create mode 100644 tests/source/non_ascii_numerics_import_asciibetically.rs create mode 100644 tests/source/non_ascii_numerics_import_versionsort.rs create mode 100644 tests/source/reorder_modules/A2/mod.rs create mode 100644 tests/source/reorder_modules/ABCD/mod.rs create mode 100644 tests/source/reorder_modules/ZYXW/mod.rs create mode 100644 tests/source/reorder_modules/ZYXW_/mod.rs create mode 100644 tests/source/reorder_modules/ZY_XW/mod.rs create mode 100644 tests/source/reorder_modules/Z_YXW/mod.rs create mode 100644 tests/source/reorder_modules/_ZYXW/mod.rs create mode 100644 tests/source/reorder_modules/_abcd/mod.rs create mode 100644 tests/source/reorder_modules/a1/mod.rs create mode 100644 tests/source/reorder_modules/abcd/mod.rs create mode 100644 tests/source/reorder_modules/disabled_style_edition_2024.rs create mode 100644 tests/source/reorder_modules/disabled_style_edition_2027.rs create mode 100644 tests/source/reorder_modules/enabled_style_edition_2015.rs create mode 100644 tests/source/reorder_modules/enabled_style_edition_2024.rs create mode 100644 tests/source/reorder_modules/enabled_style_edition_2027.rs create mode 100644 tests/source/reorder_modules/u128/mod.rs create mode 100644 tests/source/reorder_modules/u16/mod.rs create mode 100644 tests/source/reorder_modules/u256/mod.rs create mode 100644 tests/source/reorder_modules/u32/mod.rs create mode 100644 tests/source/reorder_modules/u64/mod.rs create mode 100644 tests/source/reorder_modules/u8/mod.rs create mode 100644 tests/source/reorder_modules/u_zzz/mod.rs create mode 100644 tests/source/reorder_modules/ua/mod.rs create mode 100644 tests/source/reorder_modules/usize/mod.rs create mode 100644 tests/source/reorder_modules/uz/mod.rs create mode 100644 tests/source/reorder_modules/v0/mod.rs create mode 100644 tests/source/reorder_modules/v00/mod.rs create mode 100644 tests/source/reorder_modules/v000/mod.rs create mode 100644 tests/source/reorder_modules/v001/mod.rs create mode 100644 tests/source/reorder_modules/v009/mod.rs create mode 100644 tests/source/reorder_modules/v00t/mod.rs create mode 100644 tests/source/reorder_modules/v01/mod.rs create mode 100644 tests/source/reorder_modules/v010/mod.rs create mode 100644 tests/source/reorder_modules/v09/mod.rs create mode 100644 tests/source/reorder_modules/v0s/mod.rs create mode 100644 tests/source/reorder_modules/v0u/mod.rs create mode 100644 tests/source/reorder_modules/v1/mod.rs create mode 100644 tests/source/reorder_modules/v10/mod.rs create mode 100644 tests/source/reorder_modules/v9/mod.rs create mode 100644 tests/source/reorder_modules/w005s09t/mod.rs create mode 100644 tests/source/reorder_modules/w5s009t/mod.rs create mode 100644 tests/source/reorder_modules/x64/mod.rs create mode 100644 tests/source/reorder_modules/x86/mod.rs create mode 100644 tests/source/reorder_modules/x86_128/mod.rs create mode 100644 tests/source/reorder_modules/x86_32/mod.rs create mode 100644 tests/source/reorder_modules/x86_64/mod.rs create mode 100644 tests/source/reorder_modules/x87/mod.rs create mode 100644 tests/source/reorder_modules/zyxw/mod.rs create mode 100644 tests/source/trailing-semicolon/loop-bodies-edition-2021-style-edition-2027.rs create mode 100644 tests/source/trailing-semicolon/loop-bodies-edition-2024-style-edition-2024.rs create mode 100644 tests/source/trailing-semicolon/loop-bodies.rs create mode 100644 tests/source/use-identifier-order-mixed-edition.rs create mode 100644 tests/source/use-identifier-order.rs create mode 100644 tests/target/cfg_match/format_me_please_1.rs create mode 100644 tests/target/cfg_match/format_me_please_2.rs create mode 100644 tests/target/cfg_match/format_me_please_3.rs create mode 100644 tests/target/cfg_match/format_me_please_4.rs create mode 100644 tests/target/cfg_match/lib.rs create mode 100644 tests/target/cfg_match/lib2.rs create mode 100644 tests/target/closure-block-labels.rs create mode 100644 tests/target/configs/float_literal_trailing_zero/always.rs create mode 100644 tests/target/configs/float_literal_trailing_zero/if-no-postfix.rs create mode 100644 tests/target/configs/float_literal_trailing_zero/never.rs create mode 100644 tests/target/configs/float_literal_trailing_zero/preserve.rs create mode 100644 tests/target/configs/match_arm_indent/attrs.rs create mode 100644 tests/target/configs/match_arm_indent/guards.rs create mode 100644 tests/target/configs/match_arm_indent/leading_pipes.rs create mode 100644 tests/target/configs/match_arm_indent/nested.rs create mode 100644 tests/target/configs/match_arm_indent/noindent-tabs.rs create mode 100644 tests/target/configs/match_arm_indent/noindent.rs create mode 100644 tests/target/configs/match_arm_indent/patterns.rs create mode 100644 tests/target/configs/match_arm_indent/unindent.rs create mode 100644 tests/target/ergonomic_clones.rs create mode 100644 tests/target/issue-5244/unwrapped.rs create mode 100644 tests/target/issue-5244/wrapped.rs create mode 100644 tests/target/issue-6202/long_pat.rs create mode 100644 tests/target/issue-6243.rs create mode 100644 tests/target/issue-6333-2024.rs create mode 100644 tests/target/issue-6333.rs create mode 100644 tests/target/issue-6411.rs create mode 100644 tests/target/issue_4635.rs create mode 100644 tests/target/issue_5739.rs create mode 100644 tests/target/issue_6381_style_edition_2024.rs create mode 100644 tests/target/issue_6381_style_edition_2027.rs create mode 100644 tests/target/issue_6558.rs create mode 100644 tests/target/lazy_staic_before_2027.rs rename tests/target/{no_arg_with_commnet.rs => no_arg_with_comment.rs} (100%) create mode 100644 tests/target/non_ascii_numerics_import_asciibetically.rs create mode 100644 tests/target/non_ascii_numerics_import_versionsort.rs create mode 100644 tests/target/reorder_modules/A2/mod.rs create mode 100644 tests/target/reorder_modules/ABCD/mod.rs create mode 100644 tests/target/reorder_modules/ZYXW/mod.rs create mode 100644 tests/target/reorder_modules/ZYXW_/mod.rs create mode 100644 tests/target/reorder_modules/ZY_XW/mod.rs create mode 100644 tests/target/reorder_modules/Z_YXW/mod.rs create mode 100644 tests/target/reorder_modules/_ZYXW/mod.rs create mode 100644 tests/target/reorder_modules/_abcd/mod.rs create mode 100644 tests/target/reorder_modules/a1/mod.rs create mode 100644 tests/target/reorder_modules/abcd/mod.rs create mode 100644 tests/target/reorder_modules/disabled_style_edition_2024.rs create mode 100644 tests/target/reorder_modules/disabled_style_edition_2027.rs create mode 100644 tests/target/reorder_modules/enabled_style_edition_2015.rs create mode 100644 tests/target/reorder_modules/enabled_style_edition_2024.rs create mode 100644 tests/target/reorder_modules/enabled_style_edition_2027.rs create mode 100644 tests/target/reorder_modules/u128/mod.rs create mode 100644 tests/target/reorder_modules/u16/mod.rs create mode 100644 tests/target/reorder_modules/u256/mod.rs create mode 100644 tests/target/reorder_modules/u32/mod.rs create mode 100644 tests/target/reorder_modules/u64/mod.rs create mode 100644 tests/target/reorder_modules/u8/mod.rs create mode 100644 tests/target/reorder_modules/u_zzz/mod.rs create mode 100644 tests/target/reorder_modules/ua/mod.rs create mode 100644 tests/target/reorder_modules/usize/mod.rs create mode 100644 tests/target/reorder_modules/uz/mod.rs create mode 100644 tests/target/reorder_modules/v0/mod.rs create mode 100644 tests/target/reorder_modules/v00/mod.rs create mode 100644 tests/target/reorder_modules/v000/mod.rs create mode 100644 tests/target/reorder_modules/v001/mod.rs create mode 100644 tests/target/reorder_modules/v009/mod.rs create mode 100644 tests/target/reorder_modules/v00t/mod.rs create mode 100644 tests/target/reorder_modules/v01/mod.rs create mode 100644 tests/target/reorder_modules/v010/mod.rs create mode 100644 tests/target/reorder_modules/v09/mod.rs create mode 100644 tests/target/reorder_modules/v0s/mod.rs create mode 100644 tests/target/reorder_modules/v0u/mod.rs create mode 100644 tests/target/reorder_modules/v1/mod.rs create mode 100644 tests/target/reorder_modules/v10/mod.rs create mode 100644 tests/target/reorder_modules/v9/mod.rs create mode 100644 tests/target/reorder_modules/w005s09t/mod.rs create mode 100644 tests/target/reorder_modules/w5s009t/mod.rs create mode 100644 tests/target/reorder_modules/x64/mod.rs create mode 100644 tests/target/reorder_modules/x86/mod.rs create mode 100644 tests/target/reorder_modules/x86_128/mod.rs create mode 100644 tests/target/reorder_modules/x86_32/mod.rs create mode 100644 tests/target/reorder_modules/x86_64/mod.rs create mode 100644 tests/target/reorder_modules/x87/mod.rs create mode 100644 tests/target/reorder_modules/zyxw/mod.rs create mode 100644 tests/target/trailing-semicolon/loop-bodies-edition-2021-style-edition-2027.rs create mode 100644 tests/target/trailing-semicolon/loop-bodies-edition-2024-style-edition-2024.rs create mode 100644 tests/target/trailing-semicolon/loop-bodies.rs create mode 100644 tests/target/use-identifier-order-mixed-edition.rs create mode 100644 tests/target/use-identifier-order.rs diff --git a/.github/workflows/check_diff.yml b/.github/workflows/check_diff.yml index 99daa0addf5..58425fa0c86 100644 --- a/.github/workflows/check_diff.yml +++ b/.github/workflows/check_diff.yml @@ -3,11 +3,29 @@ on: workflow_dispatch: inputs: clone_url: - description: 'Git url of a rustfmt fork to compare against the latest master rustfmt' + description: 'Git url of a rustfmt fork to compare against the latest rustfmt' required: true branch_name: description: 'Name of the feature branch on the forked repo' required: true + language_edition: + description: 'Rust language `edition` used to parse code' + required: true + default: 2015 + type: choice + options: + - 2015 + - 2018 + - 2021 + - 2024 + style_edition: + description: 'rustfmt `style_edition` used when formatting code.' + required: true + default: 2021 + type: choice + options: + - 2021 # 2015, 2018, and 2021 are all formatted the same since `style_edition` was added between 2021 and 2024 + - 2024 commit_hash: description: 'Optional commit hash from the feature branch' required: false @@ -23,11 +41,27 @@ jobs: - name: checkout uses: actions/checkout@v4 - - name: install rustup + - name: Build check_diff binary + working-directory: ./check_diff + run: cargo build --release + + - name: Run Diff Check + working-directory: ./check_diff + env: + CHECK_DIFF_LOG: info + shell: bash run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh - sh rustup-init.sh -y --default-toolchain none - rustup target add x86_64-unknown-linux-gnu + OPTIONS="" + + if [[ -n "${{ github.event.inputs.commit_hash }}" ]]; then + OPTIONS+="--commit-hash ${{ github.event.inputs.commit_hash }} " + fi + + if [[ -n "${{ github.event.inputs.rustfmt_configs }}" ]]; then + OPTIONS+="--rustfmt-config ${{ github.event.inputs.rustfmt_configs }} " + fi - - name: check diff - run: bash ${GITHUB_WORKSPACE}/ci/check_diff.sh ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} ${{ github.event.inputs.commit_hash || github.event.inputs.branch_name }} ${{ github.event.inputs.rustfmt_configs }} + target/release/check_diff ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} \ + --edition ${{ github.event.inputs.language_edition }} \ + --style-edition ${{ github.event.inputs.style_edition }} \ + $OPTIONS diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index bda374562bc..c1b04721cb1 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -2,7 +2,7 @@ name: integration on: push: branches: - - master + - main pull_request: jobs: diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 3a5e6ab5404..369b048f12f 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -2,7 +2,7 @@ name: linux on: push: branches: - - master + - main pull_request: jobs: diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 2c766d0573b..b2e8401131b 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -2,7 +2,7 @@ name: mac on: push: branches: - - master + - main pull_request: jobs: diff --git a/.github/workflows/rustdoc_check.yml b/.github/workflows/rustdoc_check.yml index 6e8a7ecd7ad..c92732366ed 100644 --- a/.github/workflows/rustdoc_check.yml +++ b/.github/workflows/rustdoc_check.yml @@ -2,7 +2,7 @@ name: rustdoc check on: push: branches: - - master + - main pull_request: jobs: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 728f1b90b13..ef8d54fb93f 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -2,7 +2,7 @@ name: windows on: push: branches: - - master + - main pull_request: jobs: diff --git a/CHANGELOG.md b/CHANGELOG.md index 8af60f60dc6..7f0470d214f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,64 @@ # Changelog +## [Unreleased] + + +## [1.9.0] 2026-02-26 + +### Fixed +- No longer strip `r#` prefix from `break` and `continue` labels [#6411](https://github.com/rust-lang/rustfmt/issues/6411) + ```rust + fn main() { + 'r#if: { + break 'r#if; + } + } + ``` +- Fix panic when sorting imports [#6333](https://github.com/rust-lang/rustfmt/issues/6333) +- Fix issue with `wrap_comments` invalidating code blocks [#6417](https://github.com/rust-lang/rustfmt/pull/6417) +- No longer remove closure block label within a macro call [#6465](https://github.com/rust-lang/rustfmt/issues/6465) +- Fix idempotency issue when normalizing imports [#6558](https://github.com/rust-lang/rustfmt/issues/6558) +- Properly split long pattern in `if-let` at the `max_width` when setting `style_edition=2027` [#6202](https://github.com/rust-lang/rustfmt/issues/6202) +- Format `lazy_static::lazy_static!` like `lazy_static!` when setting `style_edition=2027` [#6287](https://github.com/rust-lang/rustfmt/issues/6287) +- Prevent panic when rewriting missing spans that contain unicode whitespace chars [#5739](https://github.com/rust-lang/rustfmt/issues/5739) +- Allow `NotADirectory` errors when looking up rustfmt configuration files [#6624](https://github.com/rust-lang/rustfmt/pull/6624) +- Prevent panic when sorting imports starting with a `_` for `style_edition=2015|2018|2021` [#6668](https://github.com/rust-lang/rustfmt/issues/6668) +- Properly wrap long `impl trait` function parameters at the `max_width` when setting `style_edition=2027` [#6381](https://github.com/rust-lang/rustfmt/issues/6381) +- Better support for deduplicating imports when setting `imports_granularity=Module` [#6243](https://github.com/rust-lang/rustfmt/issues/6243) + +### Changed +- Stabilize `style_edition=2024` and stabilize the `style_edition` command line option [#6431](https://github.com/rust-lang/rustfmt/pull/6431) [rust-lang/rust#134929](https://github.com/rust-lang/rust/pull/134929) +- Apply version sorting to module declarations when using `style_edition=2027` [#6368](https://github.com/rust-lang/rustfmt/pull/6368) and [#6594](https://github.com/rust-lang/rustfmt/pull/6594) +- When users set the deprecated `version` config, rustfmt now gives a hint about which equivalent `style_edition` they should use [#6361](https://github.com/rust-lang/rustfmt/pull/6361) +- Correct version chunk splitting in the internal version sort algorithm [#6407](https://github.com/rust-lang/rustfmt/pull/6407) +- Extend support for single line let-chain formatting to include cases where the left hand side operand is a literal, in alignment with finalized style rules as part of let-chain stabilization [#6492](https://github.com/rust-lang/rustfmt/pull/6492) +- Begin initial formatting for `use closures` and `use chains` (`#![feature(ergonomic_clones)]`). Previously, the closure and chain was left as the developer wrote it [#6532](https://github.com/rust-lang/rustfmt/pull/6532) +- The unstable `required_version` configuration option now support cargo flavored semantic versioning using the `semver` crate [#6063](https://github.com/rust-lang/rustfmt/issues/6063) +- Top-level imports are no longer merged when setting `imports_granularity=Module`. Note that `imports_granularity=Module` is still an unstable configuration [#6191](https://github.com/rust-lang/rustfmt/issues/6191) +- Disable the `bytecount/generic-simd` optional dependency when using the `generic-simd` feature. The dependency was preventing rustfmt from building on nightly. simd support will be re-enabled once the issue has been fixed [#6807](https://github.com/rust-lang/rustfmt/pull/6807) [llogiq/bytecount#100](https://github.com/llogiq/bytecount/pull/100) +- The `trailing_semicolon` configuration option will add a trailing semicolon to the last expression in a loop body when enabled along with `edition >= 2024` and `style_edition >= 2027` [#6711](https://github.com/rust-lang/rustfmt/pull/6711) + ```rust + fn main() { + for x in 0..10 { + println!("{x}"); + } + } + ``` + + +### Added +- Add `style_edition=2027` to gate unstable formatting [#6324](https://github.com/rust-lang/rustfmt/pull/6324) +- Support discovering and formatting files via external mods imported within `cfg_match`, similar to `cfg_if` behavior [#6522](https://github.com/rust-lang/rustfmt/pull/6522) +- Add new nightly-only `match_arm_indent` option [#6525](https://github.com/rust-lang/rustfmt/pull/6525) + - See the [`match_arm_indent` configuration documentation](https://rust-lang.github.io/rustfmt/?version=v1.9.0&search=#match_arm_indent) for more details +- Add new nightly-only `float_literal_trailing_zero` option [#3187](https://github.com/rust-lang/rustfmt/issues/3187) + - See the [`float_literal_trailing_zero` configuration documentation](https://rust-lang.github.io/rustfmt/?version=v1.9.0&search=#float_literal_trailing_zero) for more details + +### Misc +- Update `term` dependency to 1.1 [#6628](https://github.com/rust-lang/rustfmt/pull/6628) +- Update `toml` dependency to 0.9.5 [#6652](https://github.com/rust-lang/rustfmt/pull/6652) + + ## [1.8.0] 2024-09-20 ### Fixed @@ -39,7 +98,7 @@ use std::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64}; ``` [style guide's version sorting algorithm]: https://doc.rust-lang.org/nightly/style-guide/#sorting -- 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) +- 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) ### Added - rustfmt now formats trailing where clauses in type aliases [#5887](https://github.com/rust-lang/rustfmt/pull/5887) @@ -133,7 +192,7 @@ ### Changed - `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). -- 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) +- 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) - 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). [log crate]: https://crates.io/crates/log @@ -298,7 +357,7 @@ ### Added -- New configuration option [`skip_macro_invocations`](https://rust-lang.github.io/rustfmt/?version=master&search=#skip_macro_invocations) [#5347](https://github.com/rust-lang/rustfmt/pull/5347) that can be used to globally define a single enumerated list of macro calls that rustfmt should skip formatting. rustfmt [currently also supports this via a custom tool attribute](https://github.com/rust-lang/rustfmt#tips), however, these cannot be used in all contexts because [custom inner attributes are unstable](https://github.com/rust-lang/rust/issues/54726) +- New configuration option [`skip_macro_invocations`](https://rust-lang.github.io/rustfmt/?version=main&search=#skip_macro_invocations) [#5347](https://github.com/rust-lang/rustfmt/pull/5347) that can be used to globally define a single enumerated list of macro calls that rustfmt should skip formatting. rustfmt [currently also supports this via a custom tool attribute](https://github.com/rust-lang/rustfmt#tips), however, these cannot be used in all contexts because [custom inner attributes are unstable](https://github.com/rust-lang/rust/issues/54726) ### Misc diff --git a/Cargo.lock b/Cargo.lock index e2ceb668ebd..64b4aaef4d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -13,12 +13,12 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.9.1" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b9d411ecbaf79885c6df4d75fff75858d5995ff25385657a28af47e82f9c36" +checksum = "24e35ed54e5ea7997c14ed4c70ba043478db1112e98263b3b035907aa197d991" dependencies = [ + "anstyle", "unicode-width", - "yansi-term", ] [[package]] @@ -37,9 +37,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.3" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" @@ -56,7 +56,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -66,7 +66,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -75,17 +75,11 @@ version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "bitflags" -version = "1.3.2" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bstr" @@ -98,9 +92,9 @@ dependencies = [ [[package]] name = "bytecount" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "camino" @@ -131,7 +125,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror", + "thiserror 1.0.40", ] [[package]] @@ -214,51 +208,52 @@ checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] name = "dirs" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ "dirs-sys", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - [[package]] name = "dirs-sys" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys", + "windows-sys 0.60.2", ] [[package]] -name = "dirs-sys-next" -version = "0.1.2" +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "redox_users", - "winapi", + "windows-sys 0.60.2", ] [[package]] -name = "either" -version = "1.6.1" +name = "fastrand" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fnv" @@ -286,6 +281,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "globset" version = "0.4.8" @@ -301,9 +308,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" [[package]] name = "heck" @@ -331,11 +338,11 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ - "autocfg", + "equivalent", "hashbrown", ] @@ -362,9 +369,25 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.141" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" @@ -402,9 +425,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "option-ext" @@ -426,40 +449,37 @@ checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] -name = "redox_syscall" -version = "0.2.13" +name = "r-efi" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "redox_users" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", + "getrandom 0.2.6", + "libredox", + "thiserror 2.0.18", ] [[package]] @@ -499,7 +519,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.8.0" +version = "1.9.0" dependencies = [ "annotate-snippets", "anyhow", @@ -514,10 +534,12 @@ dependencies = [ "itertools", "regex", "rustfmt-config_proc_macro", + "semver", "serde", "serde_json", + "tempfile", "term", - "thiserror", + "thiserror 1.0.40", "toml", "tracing", "tracing-subscriber", @@ -527,10 +549,17 @@ dependencies = [ ] [[package]] -name = "rustversion" -version = "1.0.6" +name = "rustix" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.60.2", +] [[package]] name = "ryu" @@ -549,27 +578,27 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.7" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.160" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", @@ -589,9 +618,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" dependencies = [ "serde", ] @@ -619,24 +648,35 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.14" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.60.2", +] + [[package]] name = "term" -version = "0.7.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +checksum = "a43bddab41f8626c7bdaab872bbba75f8df5847b516d77c569c746e2ae5eb746" dependencies = [ - "dirs-next", - "rustversion", - "winapi", + "windows-sys 0.60.2", ] [[package]] @@ -645,7 +685,16 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.40", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", ] [[package]] @@ -659,6 +708,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.4" @@ -670,38 +730,43 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" dependencies = [ + "indexmap", "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_parser", + "toml_writer", + "winnow", ] [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" dependencies = [ "serde", ] [[package]] -name = "toml_edit" -version = "0.19.10" +name = "toml_parser" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", "winnow", ] +[[package]] +name = "toml_writer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" + [[package]] name = "tracing" version = "0.1.37" @@ -772,9 +837,9 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "utf8parse" @@ -805,6 +870,15 @@ version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -836,13 +910,28 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", ] [[package]] @@ -851,13 +940,30 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -866,56 +972,98 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" -version = "0.4.7" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" -dependencies = [ - "memchr", -] +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" [[package]] -name = "yansi-term" -version = "0.1.2" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" -dependencies = [ - "winapi", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" diff --git a/Cargo.toml b/Cargo.toml index 6392ffbe409..6ac140f2e09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustfmt-nightly" -version = "1.8.0" +version = "1.9.0" description = "Tool to find and fix Rust formatting issues" repository = "https://github.com/rust-lang/rustfmt" readme = "README.md" @@ -30,12 +30,15 @@ path = "src/git-rustfmt/main.rs" default = ["cargo-fmt", "rustfmt-format-diff"] cargo-fmt = [] rustfmt-format-diff = [] -generic-simd = ["bytecount/generic-simd"] +# FIXME(ytmimi) re-enable "bytecount/generic-simd" to the `generic-simd` features +# once bytecount releases a fix. rustfmt's `generic-simd` features is breaking CI +# and interfering with the next subtree-sync +generic-simd = [] [dependencies] -annotate-snippets = { version = "0.9", features = ["color"] } +annotate-snippets = { version = "0.11" } anyhow = "1.0" -bytecount = "0.6.8" +bytecount = "0.6.9" cargo_metadata = "0.18" clap = { version = "4.4.2", features = ["derive"] } clap-cargo = "0.12.0" @@ -47,9 +50,9 @@ itertools = "0.12" regex = "1.7" serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0" -term = "0.7" +term = "1.1" thiserror = "1.0.40" -toml = "0.7.4" +toml = "0.9.5" tracing = { version = "0.1.37", default-features = false, features = ["std"] } tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } unicode-segmentation = "1.9" @@ -57,6 +60,10 @@ unicode-width = "0.1" unicode-properties = { version = "0.1", default-features = false, features = ["general-category"] } rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" } +semver = "1.0.21" + +[dev-dependencies] +tempfile = "3.23.0" # Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. diff --git a/Configurations.md b/Configurations.md index dd5ce73df0f..45a8b1eba87 100644 --- a/Configurations.md +++ b/Configurations.md @@ -22,7 +22,7 @@ Below you find a detailed visual guide on all the supported configuration option Maximum width of an array literal before falling back to vertical formatting. - **Default value**: `60` -- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) +- **Possible values**: any nonnegative integer that is less than or equal to the value specified for [`max_width`](#max_width) - **Stable**: Yes By default this option is set as a percentage of [`max_width`](#max_width) provided by [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `array_width` will take precedence. @@ -34,7 +34,7 @@ See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuri Maximum width of the args of a function-like attributes before falling back to vertical formatting. - **Default value**: `70` -- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) +- **Possible values**: any nonnegative integer that is less than or equal to the value specified for [`max_width`](#max_width) - **Stable**: Yes By default this option is set as a percentage of [`max_width`](#max_width) provided by [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `attr_fn_like_width` will take precedence. @@ -300,7 +300,7 @@ where Maximum width of a chain to fit on one line. - **Default value**: `60` -- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) +- **Possible values**: any nonnegative integer that is less than or equal to the value specified for [`max_width`](#max_width) - **Stable**: Yes By default this option is set as a percentage of [`max_width`](#max_width) provided by [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `chain_width` will take precedence. @@ -428,7 +428,7 @@ fn example() { Maximum length of comments. No effect unless `wrap_comments = true`. - **Default value**: `80` -- **Possible values**: any positive integer +- **Possible values**: any nonnegative integer - **Stable**: No (tracking issue: [#3349](https://github.com/rust-lang/rustfmt/issues/3349)) **Note:** A value of `0` results in [`wrap_comments`](#wrap_comments) being applied regardless of a line's width. @@ -537,14 +537,17 @@ Specifies which edition is used by the parser. - **Possible values**: `"2015"`, `"2018"`, `"2021"`, `"2024"` - **Stable**: Yes -Rustfmt is able to pick up the edition used by reading the `Cargo.toml` file if executed -through the Cargo's formatting tool `cargo fmt`. Otherwise, the edition needs to be specified -in your config file: +The `edition` option determines the Rust language edition used for parsing the code. This is important for syntax compatibility but does not directly control formatting behavior (see [style_edition](#style_edition)). + +When running `cargo fmt`, the `edition` is automatically read from the `Cargo.toml` file. However, when running `rustfmt` directly the `edition` defaults to 2015 if not explicitly configured. For consistent parsing between rustfmt and `cargo fmt` you should configure the `edition`. +For example in your `rustfmt.toml` file: ```toml edition = "2018" ``` +Alternatively, you can use the `--edition` flag when running `rustfmt` directly. + ## `empty_item_single_line` Put empty-body functions and impls on a single line @@ -583,7 +586,7 @@ Note that this is not how much whitespace is inserted, but instead the longest v doesn't get ignored when aligning. - **Default value** : 0 -- **Possible values**: any positive integer +- **Possible values**: any nonnegative integer - **Stable**: No (tracking issue: [#3372](https://github.com/rust-lang/rustfmt/issues/3372)) #### `0` (default): @@ -761,7 +764,7 @@ See also [`fn_params_layout`](#fn_params_layout) Maximum width of the args of a function call before falling back to vertical formatting. - **Default value**: `60` -- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) +- **Possible values**: any nonnegative integer that is less than or equal to the value specified for [`max_width`](#max_width) - **Stable**: Yes By default this option is set as a percentage of [`max_width`](#max_width) provided by [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `fn_call_width` will take precedence. @@ -1045,7 +1048,7 @@ fn add_one(x: i32) -> i32 { Max width for code snippets included in doc comments. Only used if [`format_code_in_doc_comments`](#format_code_in_doc_comments) is true. - **Default value**: `100` -- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) +- **Possible values**: any nonnegative integer that is less than or equal to the value specified for [`max_width`](#max_width) - **Stable**: No (tracking issue: [#5359](https://github.com/rust-lang/rustfmt/issues/5359)) ## `format_generated_files` @@ -1064,7 +1067,7 @@ This option is currently ignored for stdin (`@generated` in stdin is ignored.) Number of lines to check for a `@generated` pragma header, starting from the top of the file. Setting this value to `0` will treat all files as non-generated. When`format_generated_files` is `true`, this option has no effect. - **Default value**: `5` -- **Possible values**: any positive integer +- **Possible values**: any nonnegative integer - **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080)) See also [format_generated_files](#format_generated_files) link here. @@ -1256,6 +1259,56 @@ Control the case of the letters in hexadecimal literal values - **Possible values**: `Preserve`, `Upper`, `Lower` - **Stable**: No (tracking issue: [#5081](https://github.com/rust-lang/rustfmt/issues/5081)) +## `float_literal_trailing_zero` + +Control the presence of trailing zero in floating-point literal values + +- **Default value**: `Preserve` +- **Possible values**: `Preserve`, `Always`, `IfNoPostfix`, `Never` +- **Stable**: No (tracking issue: [#6471](https://github.com/rust-lang/rustfmt/issues/6471)) + +#### `Preserve` (default): + +Leave the literal as-is. + +```rust +fn main() { + let values = [1.0, 2., 3.0e10, 4f32]; +} +``` + +#### `Always`: + +Add a trailing zero to the literal: + +```rust +fn main() { + let values = [1.0, 2.0, 3.0e10, 4.0f32]; +} +``` + +#### `IfNoPostfix`: + +Add a trailing zero by default. If the literal contains an exponent or a suffix, the zero +and the preceding period are removed: + +```rust +fn main() { + let values = [1.0, 2.0, 3e10, 4f32]; +} +``` + +#### `Never`: + +Remove the trailing zero. If the literal contains an exponent or a suffix, the preceding +period is also removed: + +```rust +fn main() { + let values = [1., 2., 3e10, 4f32]; +} +``` + ## `hide_parse_errors` This option is deprecated and has been renamed to `show_parse_errors` to avoid confusion around the double negative default of `hide_parse_errors=false`. @@ -1662,7 +1715,7 @@ fn lorem() -> T Write an item and its attribute on the same line if their combined width is below a threshold - **Default value**: 0 -- **Possible values**: any positive integer +- **Possible values**: any nonnegative integer - **Stable**: No (tracking issue: [#3343](https://github.com/rust-lang/rustfmt/issues/3343)) ### Example @@ -1731,8 +1784,8 @@ See also: [`match_block_trailing_comma`](#match_block_trailing_comma). Controls whether to include a leading pipe on match arms -- **Default value**: `Never` -- **Possible values**: `Always`, `Never`, `Preserve` +- **Default value**: `"Never"` +- **Possible values**: `"Always"`, `"Never"`, `"Preserve"` - **Stable**: Yes #### `Never` (default): @@ -1809,6 +1862,42 @@ fn foo() { } ``` +## `match_arm_indent` + +Controls whether match arms are indented. If disabled, match arms will be formatted at the same indentation level as the outer `match` statement. Meaning that match blocks will only be indented once, not twice. + +- **Default value**: `true` +- **Possible values**: `true`, `false` +- **Stable**: No (tracking issue: [#6533](https://github.com/rust-lang/rustfmt/issues/6533)) + +#### `true` (default): + +```rust +fn main() { + match value { + Enum::A => { + let mut work = first(); + work += second(); + } + Enum::B => short_work(), + } +} +``` + +#### `false`: + +```rust +fn main() { + match value { + Enum::A => { + let mut work = first(); + work += second(); + } + Enum::B => short_work(), + } +} +``` + ## `match_block_trailing_comma` Put a trailing comma after a block based match arm (non-block arms are not affected) @@ -1850,7 +1939,7 @@ See also: [`trailing_comma`](#trailing_comma), [`match_arm_blocks`](#match_arm_b Maximum width of each line - **Default value**: `100` -- **Possible values**: any positive integer +- **Possible values**: any nonnegative integer - **Stable**: Yes See also [`error_on_line_overflow`](#error_on_line_overflow). @@ -1923,6 +2012,7 @@ use qux::{h, i}; #### `Module`: Merge imports from the same module into a single `use` statement. Conversely, imports from different modules are split into separate statements. +Does not merge top-level modules. ```rust use foo::b::{f, g}; @@ -2156,7 +2246,7 @@ fn example() { Remove nested parens. -- **Default value**: `true`, +- **Default value**: `true` - **Possible values**: `true`, `false` - **Stable**: Yes @@ -2362,9 +2452,62 @@ Require a specific version of rustfmt. If you want to make sure that the specific version of rustfmt is used in your CI, use this option. - **Default value**: `CARGO_PKG_VERSION` -- **Possible values**: any published version (e.g. `"0.3.8"`) +- **Possible values**: `semver` compliant values, such as defined on [semver.org](https://semver.org/). - **Stable**: No (tracking issue: [#3386](https://github.com/rust-lang/rustfmt/issues/3386)) +#### Match on exact version: + +```toml +required_version="1.0.0" +``` + +#### Higher or equal to: + +```toml +required_version=">=1.0.0" +``` + +#### Lower or equal to: + +```toml +required_version="<=1.0.0" +``` + +#### New minor or patch versions: + +```toml +required_version="^1.0.0" +``` + +#### New patch versions: + +```toml +required_version="~1.0.0" +``` + +#### Wildcard: + +```toml +required_version="*" # matches any version. +required_version="1.*" # matches any version with the same major version +required_version="1.0.*" # matches any version with the same major and minor version +``` + +#### Multiple versions to match: + +A comma separated list of version requirements. +The match succeeds when the current rustfmt version matches all version requirements. + +The one notable exception is that a wildcard matching any version cannot be used in the list. +For example, `*, <1.0.0` will always fail. + +Additionally, the version match will always fail if any of the version requirements contradict themselves. +Some examples of contradictory requirements are `1.*, >2.0.0`, `1.0.*, >2.0.0` and `<1.5.0, >1.10.*`. + +```toml +required_version=">=1.0.0, <2.0.0" +``` + ## `short_array_element_width_threshold` The width threshold for an array element to be considered "short". @@ -2373,7 +2516,7 @@ The layout of an array is dependent on the length of each of its elements. If the length of every element in an array is below this threshold (all elements are "short") then the array can be formatted in the mixed/compressed style, but if any one element has a length that exceeds this threshold then the array elements will have to be formatted vertically. - **Default value**: `10` -- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) +- **Possible values**: any nonnegative integer that is less than or equal to the value specified for [`max_width`](#max_width) - **Stable**: Yes #### `10` (default): @@ -2412,7 +2555,7 @@ Don't reformat out of line modules Maximum line length for single line if-else expressions. A value of `0` (zero) results in if-else expressions always being broken into multiple lines. Note this occurs when `use_small_heuristics` is set to `Off`. - **Default value**: `50` -- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) +- **Possible values**: any nonnegative integer that is less than or equal to the value specified for [`max_width`](#max_width) - **Stable**: Yes By default this option is set as a percentage of [`max_width`](#max_width) provided by [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `single_line_if_else_max_width` will take precedence. @@ -2429,7 +2572,7 @@ Note this occurs when `use_small_heuristics` is set to `Off`. By default this option is set as a percentage of [`max_width`](#max_width) provided by [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `single_line_let_else_max_width` will take precedence. - **Default value**: `50` -- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) +- **Possible values**: any nonnegative integer that is less than or equal to the value specified for [`max_width`](#max_width) - **Stable**: Yes #### `50` (default): @@ -2673,7 +2816,7 @@ See also: [`indent_style`](#indent_style). Maximum width in the body of a struct literal before falling back to vertical formatting. A value of `0` (zero) results in struct literals always being broken into multiple lines. Note this occurs when `use_small_heuristics` is set to `Off`. - **Default value**: `18` -- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) +- **Possible values**: any nonnegative integer that is less than or equal to the value specified for [`max_width`](#max_width) - **Stable**: Yes By default this option is set as a percentage of [`max_width`](#max_width) provided by [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `struct_lit_width` will take precedence. @@ -2685,7 +2828,7 @@ See also [`max_width`](#max_width), [`use_small_heuristics`](#use_small_heuristi Maximum width in the body of a struct variant before falling back to vertical formatting. A value of `0` (zero) results in struct literals always being broken into multiple lines. Note this occurs when `use_small_heuristics` is set to `Off`. - **Default value**: `35` -- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) +- **Possible values**: any nonnegative integer that is less than or equal to the value specified for [`max_width`](#max_width) - **Stable**: Yes By default this option is set as a percentage of [`max_width`](#max_width) provided by [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `struct_variant_width` will take precedence. @@ -2700,6 +2843,20 @@ Controls the edition of the [Rust Style Guide] to use for formatting ([RFC 3338] - **Possible values**: `"2015"`, `"2018"`, `"2021"`, `"2024"` (unstable variant) - **Stable**: No +This option is inferred from the [`edition`](#edition) if not specified. + +See [Rust Style Editions] for details on formatting differences between style editions. +rustfmt has a default style edition of `2015` while `cargo fmt` infers the style edition from the `edition` set in `Cargo.toml`. This can lead to inconsistencies between `rustfmt` and `cargo fmt` if the style edition is not explicitly configured. + +To ensure consistent formatting, it is recommended to specify the `style_edition` in a `rustfmt.toml` configuration file. For example: + +```toml +style_edition = "2024" +``` + +Alternatively, you can use the `--style-edition` flag when running `rustfmt` directly. + +[Rust Style Editions]: https://doc.rust-lang.org/nightly/style-guide/editions.html?highlight=editions#rust-style-editions [Rust Style Guide]: https://doc.rust-lang.org/nightly/style-guide/ [RFC 3338]: https://rust-lang.github.io/rfcs/3338-style-evolution.html @@ -2708,7 +2865,7 @@ Controls the edition of the [Rust Style Guide] to use for formatting ([RFC 3338] Number of spaces per tab - **Default value**: `4` -- **Possible values**: any positive integer +- **Possible values**: any nonnegative integer - **Stable**: Yes #### `4` (default): @@ -2890,6 +3047,7 @@ fn main() { let y = 2; let z = 3; let a = Foo { x, y, z }; + let b = Foo { x, y, z }; } ``` @@ -3062,7 +3220,9 @@ fn main() { ## `version` -This option is deprecated and has been replaced by [`style_edition`](#style_edition) +This option is deprecated and has been replaced by [`style_edition`](#style_edition). +`version = "One"` is equivalent to `style_edition = "(2015|2018|2021)"` and +`version = "Two"` is equivalent to `style_edition = "2024"` - **Default value**: `One` - **Possible values**: `One`, `Two` @@ -3112,7 +3272,7 @@ Break comments to fit on the line Note that no wrapping will happen if: 1. The comment is the start of a markdown header doc comment -2. An URL was found in the comment +2. A URL was found in the comment - **Default value**: `false` - **Possible values**: `true`, `false` diff --git a/Contributing.md b/Contributing.md index 212c5d00683..62029a71003 100644 --- a/Contributing.md +++ b/Contributing.md @@ -2,9 +2,9 @@ There are many ways to contribute to Rustfmt. This document lays out what they are and has information on how to get started. If you have any questions about -contributing or need help with anything, please ask in the WG-Rustfmt channel -on [Discord](https://discordapp.com/invite/rust-lang). Feel free to also ask questions -on issues, or file new issues specifically to get help. +contributing or need help with anything, please ask in the Rustfmt team [Zulip +channel `#t-rustfmt`][rustfmt-zulip]. Feel free to also ask questions on issues, +or file new issues specifically to get help. All contributors are expected to follow our [Code of Conduct](CODE_OF_CONDUCT.md). @@ -268,3 +268,11 @@ the config struct and parse a config file, etc. Checking an option is done by accessing the correct field on the config struct, e.g., `config.max_width()`. Most functions have a `Config`, or one can be accessed via a visitor or context of some kind. + +## Subtree syncs + +Refer to [*Subtree sync procedure*](./Subtree%20sync%20procedure.md). + + +[rustfmt-zulip]: + https://rust-lang.zulipchat.com/#narrow/channel/357797-t-rustfmt diff --git a/Processes.md b/Processes.md index 64ef20a9bd7..31445588852 100644 --- a/Processes.md +++ b/Processes.md @@ -36,7 +36,7 @@ For example, 1.0.0 -> 1.0.1: +version = "1.0.1" ``` -## 2. Push the commit to the master branch +## 2. Push the commit to the main branch E.g., https://github.com/rust-lang/rustfmt/commit/5274b49caa1a7db6ac10c76bf1a3d5710ccef569 diff --git a/README.md b/README.md index b68a942e463..77e3335cf2c 100644 --- a/README.md +++ b/README.md @@ -170,12 +170,35 @@ See [GitHub page](https://rust-lang.github.io/rustfmt/) for details. ### Rust's Editions -Rustfmt is able to pick up the edition used by reading the `Cargo.toml` file if -executed through the Cargo's formatting tool `cargo fmt`. Otherwise, the edition -needs to be specified in `rustfmt.toml`, e.g., with `edition = "2018"`. +The `edition` option determines the Rust language edition used for parsing the code. This is important for syntax compatibility but does not directly control formatting behavior (see [Style Editions](#style-editions)). + +When running `cargo fmt`, the `edition` is automatically read from the `Cargo.toml` file. However, when running `rustfmt` directly, the `edition` defaults to 2015. For consistent parsing between rustfmt and `cargo fmt`, you should configure the `edition` in your `rustfmt.toml` file: + +```toml +edition = "2018" +``` + +### Style Editions + +This option is inferred from the [`edition`](#rusts-editions) if not specified. + +See [Rust Style Editions] for details on formatting differences between style editions. +rustfmt has a default style edition of `2015` while `cargo fmt` infers the style edition from the `edition` set in `Cargo.toml`. This can lead to inconsistencies between `rustfmt` and `cargo fmt` if the style edition is not explicitly configured. + +To ensure consistent formatting, it is recommended to specify the `style_edition` in a `rustfmt.toml` configuration file. For example: + +```toml +style_edition = "2024" +``` +[Rust Style Editions]: https://doc.rust-lang.org/nightly/style-guide/editions.html?highlight=editions#rust-style-editions +[Rust Style Guide]: https://doc.rust-lang.org/nightly/style-guide/ +[RFC 3338]: https://rust-lang.github.io/rfcs/3338-style-evolution.html ## Tips +* To ensure consistent parsing between `cargo fmt` and `rustfmt`, you should configure the [`edition`](#rusts-editions) in your `rustfmt.toml` file. +* To ensure consistent formatting between `cargo fmt` and `rustfmt`, you should configure the [`style_edition`](#style-editions) in your `rustfmt.toml` file. + * For things you do not want rustfmt to mangle, use `#[rustfmt::skip]` * To prevent rustfmt from formatting a macro or an attribute, use `#[rustfmt::skip::macros(target_macro_name)]` or diff --git a/Subtree sync procedure.md b/Subtree sync procedure.md new file mode 100644 index 00000000000..ae3586a1c3b --- /dev/null +++ b/Subtree sync procedure.md @@ -0,0 +1,209 @@ +# `rustfmt` subtree sync procedure + +Note that `rustfmt` has not migrated to `josh` yet, so the git subtree sync is somewhat involved. +This procedure is mostly adapted from the `clippy` subtree sync process at +, but adapted for +`rustfmt`. We are keeping a separate copy of the instructions for `rustfmt` in case `clippy` moves +off of `git subtree` in the mean time (and also slightly adjusted to be `rustfmt`-specific. + +> [!NOTE] +> +> Note that AFAIK, eventually both `clippy` and `rustfmt` would like to move to the `josh`-sync +> workflow, just that `rustfmt` is blocked on actually doing a bidirectional sync first, while +> `clippy` is sorting out some issues related to tags and git history (due to usage of `git +> subtree`). + +## Tooling + +The `git-subtree` tooling still has a bug that prevents it from working properly with the +`rust-lang/rust` repository. This means that you need to build and use a patched version of +`git-subtree`. + +> [!NOTE] +> +> The patched version of `git-subtree` is the sources corresponding to the stale PR +> . + +On Linux, place `git-subtree` under `/usr/lib/git-core` (make sure to keep a backup copy of the +'standard' `git-subtree`), and make sure it has proper permissions: + +```sh +$ sudo cp --backup /path/to/patched/git-subtree.sh /usr/lib/git-core/git-subtree +$ sudo chmod --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree +$ sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree +``` + +> [!NOTE] +> +> Running `git subtree push` for the first time requires building a cache, which involves going +> through the entire history of `rustfmt` once. You likely will need to increase the stack limit via +> +> ```sh +> $ ulimit -s 60000 +> ``` + +> [!NOTE] +> +> The following steps assume that you have configured the `rustfmt` remote as `upstream`, i.e. +> +> ```sh +> $ git remote add upstream git@github.com:rust-lang/rustfmt +> ``` + +## Subtree push direction: syncing changes from `rust-lang/rust` to `rustfmt` + +> [!WARNING] +> +> **For this subtree-push direction, all commands described must be run within the `rust-lang/rust` +> checkout.** + +### 1. Acquire a checkout of `rust-lang/rust` + +Either acquire a clone of `rust-lang/rust`, or if you already have a checkout, make sure the +checkout is up-to-date via `git fetch`. + +### 2. Checkout the commit from the latest available nightly + + You can fetch the commit hash of the latest available nightly by inspecting `rustup check` output. + +### 3. Sync changes from the `rust`-copy of `rustfmt` to your `rustfmt` fork + +> [!WARNING] +> +> **Make sure to either use a fresh branch, e.g. `subtree-push`, or delete the branch beforehand**. +> Changes cannot be fast forwarded and you have to run this command again. + +```sh +$ git subtree push -P src/tools/rustfmt /path/to/rustfmt/checkout subtree-push +``` + +Most of the time, you will need to create a **merge commit** in the `rustfmt` repository. Note that +this must be done in the subtree repo (i.e. `rustfmt` repo) and not in the `rust`-copy of `rustfmt`. + +Assuming the `upstream` remote is the `rust-lang/rust` remote: + +```sh +$ git fetch upstream +$ git switch subtree-push +$ git merge upstream/main --no-ff +``` + +> [!WARNING] +> +> You may have to manually resolve certain merge conflicts. Pay extra attention when resolving them, +> since it's easy to accidentally resolve the conflict in incorrect ways. + +> [!TIP] +> +> Subtree syncs are one of the rare occasions where a merge commit is allowed in a PR. + +### 4. Bump the nightly toolchain version in the `rustfmt` repository + +Using the same latest nightly date (that you can obtain by inspecting `rustup check` output), +manually edit `rust-toolchain`: + +```diff + [toolchain] +-channel = "nightly-2025-04-02" ++channel = "nightly-$LATEST_NIGHTLY_DATE" + components = ["llvm-tools", "rustc-dev"] +``` + +Substituting `$LATEST_NIGHTLY_DATE` with the latest nightly date. + +Create a separate commit dedicated to making the `rust-toolchain` change. You can use [the following +commit message template](#rust-toolchain-bump-commit-message-template). + +#### `rust-toolchain` bump commit message template + +```text +chore: bump rustfmt toolchain to nightly-$LATEST_NIGHTLY_DATE + +Bumping the toolchain version as part of a git subtree push. + +current toolchain (nightly-$CURRENT_NIGHTLY_DATE): + - $CURRENT_NIGHTLY_VERSION-nightly ($CURRENT_NIGHTLY_HASH $CURRENT_NIGHTLY_DATE) + +latest toolchain (nightly-$LATEST_NIGHTLY_DATE): + - $LATEST_NIGHTLY_VERSION-nightly ($LATEST_NIGHTLY_HASH $LATEST_NIGHTLY_DATE) +``` + +Substituting the placeholders with the right information. + +> [!TIP] +> +> Example bump commit message: +> +> ```text +> chore: bump rustfmt toolchain to nightly-2025-10-07 +> +> Bumping the toolchain version as part of a git subtree push. +> +> current toolchain (nightly-2025-04-02): - 1.88.0-nightly (e2014e876 2025-04-01) +> +> latest toolchain (nightly-2025-10-07): - 1.92.0-nightly (f6aa851db 2025-10-07) +> ``` + +### 5. Open a PR against `rustfmt` + +And wait for the sync PR to be merged. The `rustfmt` maintainers will run Diff Check against the PR +to catch any unexpected formatting changes. Once Diff Check failures are investigated and are +resolved, the PR can then be merged. + +For the PR: + +- Use the title `subtree-push nightly-$LATEST_NIGHTLY_DATE` for consistency with previous + subtree-pushes. +- Include a copy of the bump commit message in the PR description for quick reference. Feel free to + include additional notes that might be helpful for the maintainers when reviewing. + +> [!TIP] +> +> Example subtree-push PR title and description: +> +> **PR title**: `subtree-push nightly-2025-10-07` +> +> **PR description**: +> +> ```text +> Bumping the toolchain version as part of a git subtree push. +> +> current toolchain (nightly-2025-04-02): +> - 1.88.0-nightly (e2014e876 2025-04-01) +> +> latest toolchain (nightly-2025-10-07): +> - 1.92.0-nightly (f6aa851db 2025-10-07) +> ``` + +> [!WARNING] +> +> Make sure to immediately follow-up with a subtree-pull direction, syncing `rustfmt` to +> `rust-lang/rust`. We need the {subtree-push, subtree-pull} directions to be performed in +> lock-step, to minimize any changes in between that makes the logistics more complex. + +## Subtree pull direction: syncing from `rustfmt` to `rust-lang/rust` + +> [!WARNING] +> +> For this **subtree-pull** direction, all commands must also be performed within the +> `rust-lang/rust` checkout. + +### 1. Make sure latest `main` of `rust-lang/rust` is checked out + +### 2. Sync `rustfmt` `main` to the `rust`-copy of `rustfmt` + +```sh +$ git switch -c rustfmt-subtree-update +$ git subtree pull -P src/tools/rustfmt /path/to/rustfmt/checkout main +``` + +### 3. Open a PR against `rust-lang/rust` + +Use the PR title + +> `rustfmt` subtree update + +so that `triagebot` will not warn against the PR containing a merge commit, and makes it easy for +`rustfmt` maintainers to discover. + +Back link to the `rustfmt` subtree-push PR as helpful context. diff --git a/check_diff/Cargo.lock b/check_diff/Cargo.lock index 2abf5af2f98..78736479e50 100644 --- a/check_diff/Cargo.lock +++ b/check_diff/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -66,6 +66,16 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -77,9 +87,14 @@ name = "check_diff" version = "0.1.0" dependencies = [ "clap", + "crossbeam-channel", + "diffy", + "ignore", "tempfile", + "toml", "tracing", "tracing-subscriber", + "walkdir", ] [[package]] @@ -128,6 +143,55 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "diffy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3041965b7a63e70447ec818a46b1e5297f7fcae3058356d226c02750c4e6cb" +dependencies = [ + "nu-ansi-term 0.50.1", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "errno" version = "0.3.9" @@ -144,12 +208,57 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +[[package]] +name = "globset" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "ignore" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata 0.4.7", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.0" @@ -205,6 +314,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.50.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +dependencies = [ + "windows-sys", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -298,6 +416,53 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -321,9 +486,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.66" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -352,6 +517,45 @@ dependencies = [ "once_cell", ] +[[package]] +name = "toml" +version = "0.9.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" + [[package]] name = "tracing" version = "0.1.40" @@ -402,7 +606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", - "nu-ansi-term", + "nu-ansi-term 0.46.0", "once_cell", "regex", "sharded-slab", @@ -431,6 +635,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "winapi" version = "0.3.9" @@ -447,6 +661,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -525,3 +748,9 @@ name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" diff --git a/check_diff/Cargo.toml b/check_diff/Cargo.toml index 4ae8a5f1f3a..50e3f0062d8 100644 --- a/check_diff/Cargo.toml +++ b/check_diff/Cargo.toml @@ -9,5 +9,9 @@ edition = "2021" clap = { version = "4.4.2", features = ["derive"] } tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } -[dev-dependencies] tempfile = "3" +walkdir = "2.5.0" +diffy = "0.4.0" +crossbeam-channel = "0.5.15" +ignore = "0.4.25" +toml = "0.9.11" diff --git a/check_diff/src/lib.rs b/check_diff/src/lib.rs index b83d67c8b6e..7c047bb0850 100644 --- a/check_diff/src/lib.rs +++ b/check_diff/src/lib.rs @@ -1,11 +1,156 @@ +use std::borrow::Cow; +use std::collections::HashMap; use std::env; -use std::io; -use std::path::Path; -use std::process::Command; -use tracing::info; +use std::fmt::{Debug, Display}; +use std::io::{self, Write}; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use std::str::FromStr; +use std::sync::{Arc, Mutex}; +use tempfile::tempdir; +use tracing::{debug, info, trace, warn}; +use walkdir::WalkDir; +#[derive(Debug, Clone, Copy)] +pub enum Edition { + /// rust edition 2015 + Edition2015, + /// rust edition 2018 + Edition2018, + /// rust edition 2021 + Edition2021, + /// rust edition 2024 + Edition2024, +} + +impl Edition { + fn as_str(&self) -> &str { + match self { + Edition::Edition2015 => "2015", + Edition::Edition2018 => "2018", + Edition::Edition2021 => "2021", + Edition::Edition2024 => "2024", + } + } +} + +impl FromStr for Edition { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "2015" => Ok(Edition::Edition2015), + "2018" => Ok(Edition::Edition2018), + "2021" => Ok(Edition::Edition2021), + "2024" => Ok(Edition::Edition2024), + _ => Err(format!("Invalid rust language edition {s}")), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum StyleEdition { + // rustfmt style_edition 2021. Also equivaluent to 2015 and 2018. + Edition2021, + // rustfmt style_edition 2024 + Edition2024, +} + +impl StyleEdition { + fn as_str(&self) -> &str { + match self { + StyleEdition::Edition2021 => "2021", + StyleEdition::Edition2024 => "2024", + } + } +} + +impl FromStr for StyleEdition { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "2015" => Ok(StyleEdition::Edition2021), + "2018" => Ok(StyleEdition::Edition2021), + "2021" => Ok(StyleEdition::Edition2021), + "2024" => Ok(StyleEdition::Edition2024), + _ => Err(format!("Invalid rustfmt style edition {s}")), + } + } +} + +pub enum FormatCodeError { + // IO Error when running code formatter + Io(std::io::Error), + /// An error occured that prevents code formatting. For example, a parse error. + CodeNotFormatted(Vec), +} + +impl From for FormatCodeError { + fn from(error: std::io::Error) -> Self { + Self::Io(error) + } +} + +impl std::fmt::Debug for FormatCodeError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Io(e) => std::fmt::Debug::fmt(e, f), + Self::CodeNotFormatted(e) => { + let data = String::from_utf8_lossy(e); + f.write_str(&data) + } + } + } +} + +pub enum CreateDiffError { + /// Couldn't create a diff because the rustfmt binary compiled from the `main` branch + /// failed to format the input. + MainRustfmtFailed(FormatCodeError), + /// Couldn't create a diff because the rustfmt binary compiled from the `feature` branch + /// failed to format the input. + FeatureRustfmtFailed(FormatCodeError), + /// Couldn't create a diff because both rustfmt binaries failed to format the input + BothRustfmtFailed { + src: FormatCodeError, + feature: FormatCodeError, + }, +} + +#[derive(Debug)] +pub enum CheckDiffError { + /// Git related errors + FailedGit(GitError), + /// Error for generic commands + FailedCommand(&'static str), + /// Error for building rustfmt from source + FailedSourceBuild(&'static str), + /// Error when obtaining binary version + FailedBinaryVersioning(PathBuf), + /// Error when obtaining cargo version + FailedCargoVersion(&'static str), + IO(std::io::Error), +} + +impl From for CheckDiffError { + fn from(error: io::Error) -> Self { + CheckDiffError::IO(error) + } +} + +impl From for CheckDiffError { + fn from(error: GitError) -> Self { + CheckDiffError::FailedGit(error) + } +} + +#[derive(Debug)] pub enum GitError { FailedClone { stdout: Vec, stderr: Vec }, + FailedRemoteAdd { stdout: Vec, stderr: Vec }, + FailedFetch { stdout: Vec, stderr: Vec }, + FailedSwitch { stdout: Vec, stderr: Vec }, IO(std::io::Error), } @@ -15,6 +160,300 @@ impl From for GitError { } } +pub struct Diff { + src_format: String, + feature_format: String, +} + +impl Display for Diff { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let patch = diffy::create_patch(self.src_format.as_str(), self.feature_format.as_str()); + write!(f, "{}", patch) + } +} + +impl Diff { + pub fn is_empty(&self) -> bool { + let patch = diffy::create_patch(self.src_format.as_str(), self.feature_format.as_str()); + patch.hunks().is_empty() + } +} + +pub struct CheckDiffRunners { + feature_runner: F, + src_runner: S, +} + +pub trait CodeFormatter { + fn format_code(&self, code: &str) -> Result; + + fn format_code_from_path>(&self, path: P) -> Result { + let code = std::fs::read_to_string(path)?; + self.format_code(&code) + } +} + +pub struct RustfmtRunner { + dynamic_library_path: String, + binary_path: PathBuf, + edition: Edition, + style_edition: StyleEdition, + config: Cow<'static, str>, +} + +impl CheckDiffRunners { + pub fn new(feature_runner: F, src_runner: S) -> Self { + Self { + feature_runner, + src_runner, + } + } +} + +impl CheckDiffRunners +where + F: CodeFormatter, + S: CodeFormatter, +{ + /// Creates a diff generated by running the source and feature binaries on the same file path + pub fn create_diff>(&self, path: P) -> Result { + let src_format = self.src_runner.format_code_from_path(&path); + let feature_format = self.feature_runner.format_code_from_path(&path); + + match (src_format, feature_format) { + (Ok(s), Ok(f)) => Ok(Diff { + src_format: s, + feature_format: f, + }), + (Err(error), Ok(_)) => { + // main formatting failed. + Err(CreateDiffError::MainRustfmtFailed(error)) + } + (Ok(_), Err(error)) => { + // feature formatting failed + Err(CreateDiffError::FeatureRustfmtFailed(error)) + } + (Err(src_error), Err(feature_error)) => { + // Both main formatting and feature formatting failed + Err(CreateDiffError::BothRustfmtFailed { + src: src_error, + feature: feature_error, + }) + } + } + } +} + +impl RustfmtRunner { + fn get_binary_version(&self) -> Result { + let Ok(command) = Command::new(&self.binary_path) + .env( + dynamic_library_path_env_var_name(), + &self.dynamic_library_path, + ) + .args(["--version"]) + .output() + else { + return Err(CheckDiffError::FailedBinaryVersioning( + self.binary_path.clone(), + )); + }; + + Ok(buffer_into_utf8_lossy(command.stdout)) + } + + fn command_line_configs(&self) -> &str { + &self.config + } +} + +/// Convert a buffer of u8 into a String. +fn buffer_into_utf8_lossy(buffer: Vec) -> String { + let mut s = match String::from_utf8(buffer) { + Ok(s) => s, + Err(e) => String::from_utf8_lossy(e.as_bytes()).to_string(), + }; + s.truncate(s.trim_end().len()); + s +} + +/// Returns the name of the environment variable used to search for dynamic libraries. +/// This is the same logic that cargo uses when setting these environment variables +fn dynamic_library_path_env_var_name() -> &'static str { + if cfg!(windows) { + "PATH" + } else if cfg!(target_os = "macos") { + "DYLD_FALLBACK_LIBRARY_PATH" + } else if cfg!(target_os = "aix") { + "LIBPATH" + } else { + "LD_LIBRARY_PATH" + } +} + +impl CodeFormatter for RustfmtRunner { + // When rustfmt knows the file path it's able to skip formatting for files listed in the repo's + // rustfmt.toml `ignore` list. For example, this helps us skip files in r-l/rust that have + // been explicitly skipped because trying to format them causes rustfmt to hang or rustfmt. + // doesn't do a good job at formatting those files. + fn format_code_from_path>(&self, path: P) -> Result { + let command = Command::new(&self.binary_path) + .env( + dynamic_library_path_env_var_name(), + &self.dynamic_library_path, + ) + .args([ + "--edition", + self.edition.as_str(), + "--style-edition", + self.style_edition.as_str(), + "--unstable-features", + "--skip-children", + "--emit=stdout", + self.command_line_configs(), + ]) + .arg(path.as_ref()) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + let output = command.wait_with_output()?; + let formatted_code = buffer_into_utf8_lossy(output.stdout); + + match output.status.code() { + Some(0) => Ok(formatted_code), + Some(_) | None => { + if !formatted_code.is_empty() { + Ok(formatted_code) + } else { + Err(FormatCodeError::CodeNotFormatted(output.stderr)) + } + } + } + } + + // Run rusfmt to see if a diff is produced. Runs on the code specified + // + // Parameters: + // code: Code to run the binary on + // config: Any additional configuration options to pass to rustfmt + // + fn format_code(&self, code: &str) -> Result { + let mut command = Command::new(&self.binary_path) + .env( + dynamic_library_path_env_var_name(), + &self.dynamic_library_path, + ) + .args([ + "--edition", + self.edition.as_str(), + "--style-edition", + self.style_edition.as_str(), + "--unstable-features", + "--skip-children", + "--emit=stdout", + self.command_line_configs(), + ]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + command.stdin.as_mut().unwrap().write_all(code.as_bytes())?; + let output = command.wait_with_output()?; + let formatted_code = buffer_into_utf8_lossy(output.stdout); + + match output.status.code() { + Some(0) => Ok(formatted_code), + Some(_) | None => { + if !formatted_code.is_empty() { + Ok(formatted_code) + } else { + Err(FormatCodeError::CodeNotFormatted(output.stderr)) + } + } + } + } +} + +const DEFAULT_CONFIG: &str = "--config=error_on_line_overflow=false,error_on_unformatted=false"; + +/// Creates a configuration in the following form: +/// =, =, ... +fn create_config_arg>(configs: Option<&[T]>) -> Cow<'static, str> { + let Some(configs) = configs else { + return Cow::Borrowed(DEFAULT_CONFIG); + }; + + let mut configs_len = 0; + let mut num_configs = 0; + + // Determine how many non empty configs we've got + for c in configs.iter().map(AsRef::as_ref) { + if c.is_empty() { + continue; + } + + configs_len += c.len(); + num_configs += 1; + } + + if num_configs == 0 { + // All configs were empty so return the default. + return Cow::Borrowed(DEFAULT_CONFIG); + } + + // We need capacity for the default configs len + one ',' per config + total config element len + let mut result = String::with_capacity(DEFAULT_CONFIG.len() + num_configs + configs_len); + + for c in configs.iter().map(AsRef::as_ref) { + result.push(','); + result.push_str(c); + } + + Cow::Owned(result) +} + +pub struct Repository

{ + /// Name of the repository + name: String, + /// Path to the repository on the local file system + dir_path: P, +} + +impl

Repository

{ + /// Initialize a new Repository + pub fn new(git_url: &str, dir_path: P) -> Self { + let name = get_repo_name(git_url).to_string(); + Self { name, dir_path } + } + + /// Get the `name` of the repository + pub fn name(&self) -> &str { + &self.name + } + + /// Get the absolute path to where this repository was cloned + pub fn path(&self) -> &Path + where + P: AsRef, + { + self.dir_path.as_ref() + } + + /// Get the relative path of a file contained in this repository + pub fn relative_path<'f, F>(&self, file: &'f F) -> &'f Path + where + P: AsRef, + F: AsRef, + { + file.as_ref() + .strip_prefix(self.dir_path.as_ref()) + .unwrap_or(file.as_ref()) + } +} + /// Clone a git repository /// /// Parameters: @@ -43,16 +482,439 @@ pub fn clone_git_repo(url: &str, dest: &Path) -> Result<(), GitError> { return Err(error); } - info!("Successfully clone repository."); - return Ok(()); + info!("Successfully cloned repository {url} to {}", dest.display()); + Ok(()) +} + +pub fn git_remote_add(url: &str) -> Result<(), GitError> { + let git_cmd = Command::new("git") + .args(["remote", "add", "feature", url]) + .output()?; + + // if the git command does not return successfully, + // any command on the repo will fail. So fail fast. + if !git_cmd.status.success() { + let error = GitError::FailedRemoteAdd { + stdout: git_cmd.stdout, + stderr: git_cmd.stderr, + }; + return Err(error); + } + + info!("Successfully added remote: {url}"); + Ok(()) +} + +pub fn git_fetch(branch_name: &str) -> Result<(), GitError> { + let git_cmd = Command::new("git") + .args(["fetch", "feature", branch_name]) + .output()?; + + // if the git command does not return successfully, + // any command on the repo will fail. So fail fast. + if !git_cmd.status.success() { + let error = GitError::FailedFetch { + stdout: git_cmd.stdout, + stderr: git_cmd.stderr, + }; + return Err(error); + } + + info!("Successfully fetched: {branch_name}"); + Ok(()) +} + +pub fn git_switch(git_ref: &str, should_detach: bool) -> Result<(), GitError> { + let detach_arg = if should_detach { "--detach" } else { "" }; + let args = ["switch", git_ref, detach_arg]; + let output = Command::new("git") + .args(args.iter().filter(|arg| !arg.is_empty())) + .output()?; + if !output.status.success() { + tracing::error!("Git switch failed: {output:?}"); + let error = GitError::FailedSwitch { + stdout: output.stdout, + stderr: output.stderr, + }; + return Err(error); + } + info!("Successfully switched to {git_ref}"); + Ok(()) } pub fn change_directory_to_path(dest: &Path) -> io::Result<()> { let dest_path = Path::new(&dest); - env::set_current_dir(&dest_path)?; + env::set_current_dir(dest_path)?; info!( - "Current directory: {}", + "Setting current directory to: {}", env::current_dir().unwrap().display() ); - return Ok(()); + Ok(()) +} + +pub fn get_dynamic_library_path(dir: &Path) -> Result { + let Ok(command) = Command::new("rustc") + .current_dir(dir) + .args(["--print", "sysroot"]) + .output() + else { + return Err(CheckDiffError::FailedCommand("Error getting sysroot")); + }; + let mut sysroot = buffer_into_utf8_lossy(command.stdout); + sysroot.push_str("/lib"); + Ok(sysroot) +} + +pub fn get_cargo_version() -> Result { + let Ok(command) = Command::new("cargo").args(["--version"]).output() else { + return Err(CheckDiffError::FailedCargoVersion( + "Failed to obtain cargo version", + )); + }; + + Ok(buffer_into_utf8_lossy(command.stdout)) +} + +/// Obtains the ld_lib path and then builds rustfmt from source +/// If that operation succeeds, the source is then copied to the output path specified +pub fn build_rustfmt_from_src>( + binary_path: PathBuf, + dir: &Path, + edition: Edition, + style_edition: StyleEdition, + config: Option<&[T]>, +) -> Result { + // Because we're building standalone binaries we need to set the dynamic library path + // so each rustfmt binary can find it's runtime dependencies. + let dynamic_library_path = get_dynamic_library_path(dir)?; + + info!("Building rustfmt from source"); + let Ok(_) = Command::new("cargo") + .current_dir(dir) + .args(["build", "-q", "--release", "--bin", "rustfmt"]) + .output() + else { + return Err(CheckDiffError::FailedSourceBuild( + "Error building rustfmt from source", + )); + }; + + std::fs::copy(dir.join("target/release/rustfmt"), &binary_path)?; + + Ok(RustfmtRunner { + dynamic_library_path, + binary_path, + edition, + style_edition, + config: create_config_arg(config), + }) +} + +// Compiles and produces two rustfmt binaries. +// One for the current main branch, and another for the feature branch +// Parameters: +// dest: Directory where rustfmt will be cloned +pub fn compile_rustfmt>( + dest: &Path, + remote_repo_url: String, + feature_branch: String, + edition: Edition, + style_edition: StyleEdition, + commit_hash: Option, + config: Option<&[T]>, +) -> Result, CheckDiffError> { + const RUSTFMT_REPO: &str = "https://github.com/rust-lang/rustfmt.git"; + + clone_git_repo(RUSTFMT_REPO, dest)?; + change_directory_to_path(dest)?; + git_remote_add(remote_repo_url.as_str())?; + git_fetch(feature_branch.as_str())?; + + let cargo_version = get_cargo_version()?; + info!("Compiling with {}", cargo_version); + let src_runner = build_rustfmt_from_src( + dest.join("src_rustfmt"), + dest, + edition, + style_edition, + config, + )?; + let should_detach = commit_hash.is_some(); + git_switch( + commit_hash.as_ref().unwrap_or(&feature_branch), + should_detach, + )?; + + let feature_runner = build_rustfmt_from_src( + dest.join("feature_rustfmt"), + dest, + edition, + style_edition, + config, + )?; + info!("RUSFMT_BIN {}", src_runner.get_binary_version()?); + let dynamic_library_path_env_var = dynamic_library_path_env_var_name(); + info!( + "Runtime dependencies for (main) rustfmt -- {}: {}", + dynamic_library_path_env_var, src_runner.dynamic_library_path + ); + info!("FEATURE_BIN {}", feature_runner.get_binary_version()?); + info!( + "Runtime dependencies for ({}) rustfmt -- {}: {}", + feature_branch, dynamic_library_path_env_var, feature_runner.dynamic_library_path + ); + + Ok(CheckDiffRunners { + src_runner, + feature_runner, + }) +} + +fn read_rustfmt_ignore_list(rustfmt_toml_path: &Path) -> Vec { + let Ok(file_content) = std::fs::read_to_string(rustfmt_toml_path) else { + return Vec::new(); + }; + + let Ok(mut data) = file_content.parse::() else { + return Vec::new(); + }; + + let Some(toml::Value::Array(ignore_list)) = data.remove("ignore") else { + return Vec::new(); + }; + + ignore_list + .into_iter() + .map(toml::Value::try_into) + .collect::>() + .unwrap_or_default() +} + +// Iterator over all rust files in a directory. +// +// Ignores files list in the root `.rustfmt.toml` or `rustfmt.toml` configuration files. +pub struct RustFmtFileFinder<'a, P> { + ignore_set: ignore::gitignore::Gitignore, + repo: &'a Repository

, +} + +impl<'a, P> RustFmtFileFinder<'a, P> +where + P: AsRef, +{ + pub fn from_repository(repo: &'a Repository

) -> Self { + let root = repo.path(); + let mut ignore_builder = ignore::gitignore::GitignoreBuilder::new(root); + + let repo_name = repo.name(); + for rustfmt_config_file in [".rustfmt.toml", "rustfmt.toml"] { + let rustfmt_toml_path = root.join(rustfmt_config_file); + for ignore_path in read_rustfmt_ignore_list(&rustfmt_toml_path) { + debug!("Adding {ignore_path} to the set of ignored files for '{repo_name}'"); + let _ = ignore_builder.add_line(None, &ignore_path); + } + } + + Self { + repo, + ignore_set: ignore_builder + .build() + .unwrap_or(ignore::gitignore::Gitignore::empty()), + } + } + + pub fn iter(&self) -> impl Iterator + use<'_, P> { + WalkDir::new(self.repo.path()) + .into_iter() + .filter_map(|e| match e.ok() { + Some(entry) => { + let path = entry.path(); + if path.is_file() + && path.extension().is_some_and(|ext| ext == "rs") + && !self + .ignore_set + .matched_path_or_any_parents(path, false) + .is_ignore() + { + return Some(entry.into_path()); + } + None + } + None => None, + }) + } +} + +/// Encapsulate the logic used to clone repositories for the diff check +pub fn clone_repositories_for_diff_check( + repositories: &[&str], +) -> Vec> { + // Use a Hashmap to deduplicate any repositories + let map = Arc::new(Mutex::new(HashMap::new())); + + std::thread::scope(|s| { + for url in repositories { + let map = Arc::clone(&map); + + s.spawn(move || { + let repo_name = get_repo_name(url); + info!("Processing repo: {repo_name}"); + let Ok(tmp_dir) = tempdir() else { + warn!( + "Failed to create a tempdir for {}. Can't check formatting diff for {}", + &url, repo_name + ); + return; + }; + + let Ok(_) = clone_git_repo(url, tmp_dir.path()) else { + warn!( + "Failed to clone repo {}. Can't check formatting diff for {}", + &url, repo_name + ); + return; + }; + + let repo = Repository::new(url, tmp_dir); + map.lock().unwrap().insert(repo_name.to_string(), repo); + }); + } + }); + + let map = match Arc::into_inner(map) + .expect("All other threads are done") + .into_inner() + { + Ok(map) => map, + Err(e) => e.into_inner(), + }; + + map.into_values().collect() +} + +/// Calculates the number of errors when running the compiled binary and the feature binary on the +/// repo specified with the specific configs. +pub fn check_diff_for_file<'repo, P: AsRef, F: AsRef>( + runners: &CheckDiffRunners, + repo: &'repo Repository

, + file: F, +) -> Result<(), (Diff, F, &'repo Repository

)> { + let relative_path = repo.relative_path(&file); + let repo_name = repo.name(); + + trace!( + "Formatting '{0}' file {0}/{1}", + repo_name, + relative_path.display() + ); + + match runners.create_diff(file.as_ref()) { + Ok(diff) => { + if !diff.is_empty() { + Err((diff, file, repo)) + } else { + trace!( + "No diff found in '{0}' when formatting {0}/{1}", + repo_name, + relative_path.display(), + ); + Ok(()) + } + } + Err(CreateDiffError::MainRustfmtFailed(e)) => { + debug!( + "`main` rustfmt failed to format {}/{}\n{:?}", + repo_name, + relative_path.display(), + e, + ); + Ok(()) + } + Err(CreateDiffError::FeatureRustfmtFailed(e)) => { + debug!( + "`feature` rustfmt failed to format {}/{}\n{:?}", + repo_name, + relative_path.display(), + e, + ); + Ok(()) + } + Err(CreateDiffError::BothRustfmtFailed { src, feature }) => { + debug!( + "Both rustfmt binaries failed to format {}/{}\n{:?}\n{:?}", + repo_name, + relative_path.display(), + src, + feature, + ); + Ok(()) + } + } +} + +/// parse out the repository name from a GitHub Repository name. +pub fn get_repo_name(git_url: &str) -> &str { + let strip_git_prefix = git_url.strip_suffix(".git").unwrap_or(git_url); + let (_, repo_name) = strip_git_prefix + .rsplit_once('/') + .unwrap_or(("", strip_git_prefix)); + repo_name +} + +pub fn check_diff<'repo, P, F, M>( + runners: &CheckDiffRunners, + repositories: &'repo [Repository

], + worker_threads: std::num::NonZeroU8, +) -> Vec<(Diff, PathBuf, &'repo Repository

)> +where + P: AsRef + Sync + Send, + F: CodeFormatter + Sync, + M: CodeFormatter + Sync, +{ + let (tx, rx) = crossbeam_channel::unbounded(); + + let errors = std::thread::scope(|s| { + // Spawn producer threads that find files to check + for repo in repositories.iter() { + let tx = tx.clone(); + s.spawn(move || { + let file_finder = RustFmtFileFinder::from_repository(repo); + for file in file_finder.iter() { + let _ = tx.send((file, repo)); + } + }); + } + + // Drop the first `tx` we created. Now there's exactly one `tx` per producer thread so when + // each producer thread finishes the receiving threads will start to get Err(RecvError) + // when calling `rx.recv()` and they'll know to stop processing files. + // When all scoped threads end we'll know we're done with processing and we can return + // any errors we found to the caller. + drop(tx); + + let errors = Arc::new(Mutex::new(Vec::with_capacity(10))); + + // spawn receiver threads used to process all files: + for _ in 0..u8::from(worker_threads) { + let errors = Arc::clone(&errors); + let rx = rx.clone(); + s.spawn(move || { + while let Ok((file, repo)) = rx.recv() { + if let Err(e) = check_diff_for_file(runners, repo, file) { + // Push errors to report on later + errors.lock().unwrap().push(e); + } + } + }); + } + errors + }); + + match Arc::into_inner(errors) + .expect("All other threads are done") + .into_inner() + { + Ok(e) => e, + Err(e) => e.into_inner(), + } } diff --git a/check_diff/src/main.rs b/check_diff/src/main.rs index 01c5926c490..60aee6ee2cb 100644 --- a/check_diff/src/main.rs +++ b/check_diff/src/main.rs @@ -1,12 +1,57 @@ +use std::io::Error; +use std::process::ExitCode; + +use check_diff::{ + Edition, StyleEdition, check_diff, clone_repositories_for_diff_check, compile_rustfmt, +}; use clap::Parser; +use tempfile::tempdir; +use tracing::{error, info}; + +/// A curated set of `rust-lang/*` and popular ecosystem repositories to compare `rustfmt`s against. +const REPOS: &[&str] = &[ + // `rust-lang/*` repositories. + "https://github.com/rust-lang/cargo.git", + "https://github.com/rust-lang/futures-rs.git", + "https://github.com/rust-lang/log.git", + "https://github.com/rust-lang/mdBook.git", + "https://github.com/rust-lang/miri.git", + "https://github.com/rust-lang/packed_simd.git", + "https://github.com/rust-lang/rust-analyzer.git", + "https://github.com/rust-lang/rust-bindgen.git", + "https://github.com/rust-lang/rust-clippy.git", + "https://github.com/rust-lang/rust-semverver.git", + "https://github.com/rust-lang/rustfmt.git", + "https://github.com/rust-lang/rust.git", + "https://github.com/rust-lang/rustlings.git", + "https://github.com/rust-lang/rustup.git", + // Ecosystem repositories + "https://github.com/actix/actix.git", + "https://github.com/bitflags/bitflags.git", + "https://github.com/denoland/deno.git", + "https://github.com/dtolnay/anyhow.git", + "https://github.com/dtolnay/syn.git", + "https://github.com/dtolnay/thiserror.git", + "https://github.com/hyperium/hyper.git", + "https://github.com/rustls/rustls.git", + "https://github.com/serde-rs/serde.git", + "https://github.com/SergioBenitez/Rocket.git", + "https://github.com/Stebalien/tempfile.git", +]; /// Inputs for the check_diff script #[derive(Parser)] struct CliInputs { - /// Git url of a rustfmt fork to compare against the latest master rustfmt + /// Git url of a rustfmt fork to compare against the latest main rustfmt remote_repo_url: String, /// Name of the feature branch on the forked repo feature_branch: String, + /// Rust language `edition` used to parse code. Possible values {2015, 2018, 2021, 2024} + #[arg(short, long, default_value = "2015")] + edition: Edition, + /// rustfmt `style_edition` used when formatting code. Possible vales {2015, 2018, 2021, 2024}. + #[arg(short, long, default_value = "2021")] + style_edition: StyleEdition, /// Optional commit hash from the feature branch #[arg(short, long)] commit_hash: Option, @@ -14,8 +59,61 @@ struct CliInputs { /// pass when running the feature branch #[arg(value_delimiter = ',', short, long, num_args = 1..)] rustfmt_config: Option>, + /// How many threads should check for formatting diffs. + // Choosing 16 as the default since that's a common multiple of available CPU cores. + #[arg(short, long, default_value_t = std::num::NonZeroU8::new(16).unwrap())] + worker_threads: std::num::NonZeroU8, } -fn main() { - let _args = CliInputs::parse(); +fn main() -> Result { + tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_env("CHECK_DIFF_LOG")) + .init(); + let args = CliInputs::parse(); + let tmp_dir = tempdir()?; + info!("Created tmp_dir {:?}", tmp_dir); + + let compilation_result = compile_rustfmt( + tmp_dir.path(), + args.remote_repo_url, + args.feature_branch, + args.edition, + args.style_edition, + args.commit_hash, + args.rustfmt_config.as_deref(), + ); + + let check_diff_runners = match compilation_result { + Ok(runner) => runner, + Err(e) => { + error!("Failed to compile rustfmt:\n{e:?}"); + return Ok(ExitCode::FAILURE); + } + }; + + // Clone all repositories we plan to check + let repositories = clone_repositories_for_diff_check(REPOS); + + info!("Starting the Diff Check"); + let errors = check_diff(&check_diff_runners, &repositories, args.worker_threads); + + if errors.is_empty() { + info!("No diff found 😊"); + return Ok(ExitCode::SUCCESS); + } + + for (diff, file, repo) in errors.iter() { + let repo_name = repo.name(); + let relative_path = repo.relative_path(&file); + + error!( + "Diff found in '{0}' when formatting {0}/{1}\n{2}", + repo_name, + relative_path.display(), + diff, + ); + } + + error!("{} formatting diffs found 💔", errors.len()); + Ok(ExitCode::FAILURE) } diff --git a/check_diff/tests/check_diff.rs b/check_diff/tests/check_diff.rs new file mode 100644 index 00000000000..b1b4001bac1 --- /dev/null +++ b/check_diff/tests/check_diff.rs @@ -0,0 +1,97 @@ +use check_diff::{ + CheckDiffError, CheckDiffRunners, CodeFormatter, FormatCodeError, Repository, + RustFmtFileFinder, check_diff, +}; +use std::fs::File; +use tempfile::Builder; + +struct DoNothingFormatter; + +impl CodeFormatter for DoNothingFormatter { + fn format_code(&self, _code: &str) -> Result { + Ok(String::new()) + } +} + +/// Formatter that adds a white space to the end of the codd +struct AddWhiteSpaceFormatter; + +impl CodeFormatter for AddWhiteSpaceFormatter { + fn format_code(&self, code: &str) -> Result { + let result = code.to_string() + " "; + Ok(result) + } +} + +#[test] +fn search_for_files_correctly_non_nested() -> Result<(), Box> { + let dir = Builder::new().tempdir_in("").unwrap(); + let file_path = dir.path().join("test.rs"); + let _tmp_file = File::create(file_path)?; + + let repo = Repository::new("", dir.path()); + let file_finder = RustFmtFileFinder::from_repository(&repo); + + let mut count = 0; + for _ in file_finder.iter() { + count += 1; + } + + assert_eq!(count, 1); + + Ok(()) +} + +#[test] +fn search_for_files_correctly_nested() -> Result<(), Box> { + let dir = Builder::new().tempdir_in("").unwrap(); + let file_path = dir.path().join("test.rs"); + let _tmp_file = File::create(file_path)?; + + let nested_dir = Builder::new().tempdir_in(dir.path()).unwrap(); + let nested_file_path = nested_dir.path().join("nested.rs"); + let _ = File::create(nested_file_path)?; + + let repo = Repository::new("", dir.path()); + let file_finder = RustFmtFileFinder::from_repository(&repo); + + let mut count = 0; + for _ in file_finder.iter() { + count += 1; + } + + assert_eq!(count, 2); + + Ok(()) +} + +#[test] +fn check_diff_test_no_formatting_difference() -> Result<(), CheckDiffError> { + let runners = CheckDiffRunners::new(DoNothingFormatter, DoNothingFormatter); + + let dir = Builder::new().tempdir_in("").unwrap(); + let file_path = dir.path().join("test.rs"); + let _tmp_file = File::create(file_path)?; + let repo = Repository::new("https://github.com/rust-lang/rustfmt.git", dir); + let repos = [repo]; + let workers = std::num::NonZeroU8::new(1).unwrap(); + + let errors = check_diff(&runners, &repos, workers); + assert_eq!(errors.len(), 0); + Ok(()) +} + +#[test] +fn check_diff_test_formatting_difference() -> Result<(), CheckDiffError> { + let runners = CheckDiffRunners::new(DoNothingFormatter, AddWhiteSpaceFormatter); + let dir = Builder::new().tempdir_in("").unwrap(); + let file_path = dir.path().join("test.rs"); + let _tmp_file = File::create(file_path)?; + let repo = Repository::new("https://github.com/rust-lang/rustfmt.git", dir); + let repos = [repo]; + let workers = std::num::NonZeroU8::new(1).unwrap(); + + let errors = check_diff(&runners, &repos, workers); + assert_ne!(errors.len(), 0); + Ok(()) +} diff --git a/ci/check_diff.sh b/ci/check_diff.sh deleted file mode 100755 index 2a29cb138ef..00000000000 --- a/ci/check_diff.sh +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/bash - -set -e - -function print_usage() { - echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]" -} - -if [ $# -le 1 ]; then - print_usage - exit 1 -fi - -REMOTE_REPO=$1 -FEATURE_BRANCH=$2 -OPTIONAL_COMMIT_HASH=$3 -OPTIONAL_RUSTFMT_CONFIGS=$4 - -# OUTPUT array used to collect all the status of running diffs on various repos -STATUSES=() - -# Clone a git repository and cd into it. -# -# Parameters: -# $1: git clone url -# $2: directory where the repo should be cloned -function clone_repo() { - GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2 -} - -# Initialize Git submodules for the repo. -# -# Parameters -# $1: list of directories to initialize -function init_submodules() { - git submodule update --init $1 -} - -# Run rusfmt with the --check flag to see if a diff is produced. -# -# Parameters: -# $1: Path to a rustfmt binary -# $2: Output file path for the diff -# $3: Any additional configuration options to pass to rustfmt -# -# Globals: -# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 -function create_diff() { - local config; - if [ -z "$3" ]; then - config="--config=error_on_line_overflow=false,error_on_unformatted=false" - else - config="--config=error_on_line_overflow=false,error_on_unformatted=false,$OPTIONAL_RUSTFMT_CONFIGS" - fi - - for i in `find . | grep "\.rs$"` - do - $1 --unstable-features --skip-children --check --color=always $config $i >> $2 2>/dev/null - done -} - -# Run the master rustfmt binary and the feature branch binary in the current directory and compare the diffs -# -# Parameters -# $1: Name of the repository (used for logging) -# -# Globals: -# $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt` -# $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt` -# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 -function check_diff() { - echo "running rustfmt (master) on $1" - create_diff $RUSFMT_BIN rustfmt_diff.txt - - echo "running rustfmt (feature) on $1" - create_diff $FEATURE_BIN feature_diff.txt $OPTIONAL_RUSTFMT_CONFIGS - - echo "checking diff" - local diff; - # we don't add color to the diff since we added color when running rustfmt --check. - # tail -n + 6 removes the git diff header info - # cut -c 2- removes the leading diff characters("+","-"," ") from running git diff. - # Again, the diff output we care about was already added when we ran rustfmt --check - diff=$( - git --no-pager diff --color=never \ - --unified=0 --no-index rustfmt_diff.txt feature_diff.txt 2>&1 | tail -n +6 | cut -c 2- - ) - - if [ -z "$diff" ]; then - echo "no diff detected between rustfmt and the feature branch" - return 0 - else - echo "$diff" - return 1 - fi -} - -# Compiles and produces two rustfmt binaries. -# One for the current master, and another for the feature branch -# -# Parameters: -# $1: Directory where rustfmt will be cloned -# -# Globals: -# $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test -# $FEATURE_BRANCH: Name of the feature branch -# $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided -function compile_rustfmt() { - RUSTFMT_REPO="https://github.com/rust-lang/rustfmt.git" - clone_repo $RUSTFMT_REPO $1 - git remote add feature $REMOTE_REPO - git fetch feature $FEATURE_BRANCH - - CARGO_VERSION=$(cargo --version) - echo -e "\ncompiling with $CARGO_VERSION\n" - - # Because we're building standalone binaries we need to set `LD_LIBRARY_PATH` so each - # binary can find it's runtime dependencies. See https://github.com/rust-lang/rustfmt/issues/5675 - # This will prepend the `LD_LIBRARY_PATH` for the master rustfmt binary - export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH - - echo "Building rustfmt from src" - cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt - - if [ -z "$OPTIONAL_COMMIT_HASH" ] || [ "$FEATURE_BRANCH" = "$OPTIONAL_COMMIT_HASH" ]; then - git switch $FEATURE_BRANCH - else - git switch $OPTIONAL_COMMIT_HASH --detach - fi - - # This will prepend the `LD_LIBRARY_PATH` for the feature branch rustfmt binary. - # In most cases the `LD_LIBRARY_PATH` should be the same for both rustfmt binaries that we build - # in `compile_rustfmt`, however, there are scenarios where each binary has different runtime - # dependencies. For example, during subtree syncs we bump the nightly toolchain required to build - # rustfmt, and therefore the feature branch relies on a newer set of runtime dependencies. - export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH - - echo "Building feature rustfmt from src" - cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt - - echo -e "\nRuntime dependencies for rustfmt -- LD_LIBRARY_PATH: $LD_LIBRARY_PATH" - - RUSFMT_BIN=$1/rustfmt - RUSTFMT_VERSION=$($RUSFMT_BIN --version) - echo -e "\nRUSFMT_BIN $RUSTFMT_VERSION\n" - - FEATURE_BIN=$1/feature_rustfmt - FEATURE_VERSION=$($FEATURE_BIN --version) - echo -e "FEATURE_BIN $FEATURE_VERSION\n" -} - -# Check the diff for running rustfmt and the feature branch on all the .rs files in the repo. -# -# Parameters -# $1: Clone URL for the repo -# $2: Name of the repo (mostly used for logging) -# $3: Path to any submodules that should be initialized -function check_repo() { - WORKDIR=$(pwd) - REPO_URL=$1 - REPO_NAME=$2 - SUBMODULES=$3 - - local tmp_dir; - tmp_dir=$(mktemp -d -t $REPO_NAME-XXXXXXXX) - clone_repo $REPO_URL $tmp_dir - - if [ ! -z "$SUBMODULES" ]; then - init_submodules $SUBMODULES - fi - - - # rustfmt --check returns 1 if a diff was found - # Also check_diff returns 1 if there was a diff between master rustfmt and the feature branch - # so we want to ignore the exit status check - set +e - check_diff $REPO_NAME - # append the status of running `check_diff` to the STATUSES array - STATUSES+=($?) - set -e - - echo -e "removing tmp_dir $tmp_dir\n\n" - rm -rf $tmp_dir - cd $WORKDIR -} - -function main() { - tmp_dir=$(mktemp -d -t rustfmt-XXXXXXXX) - echo Created tmp_dir $tmp_dir - - compile_rustfmt $tmp_dir - - # run checks - check_repo "https://github.com/rust-lang/rust.git" rust-lang-rust - check_repo "https://github.com/rust-lang/cargo.git" cargo - check_repo "https://github.com/rust-lang/miri.git" miri - check_repo "https://github.com/rust-lang/rust-analyzer.git" rust-analyzer - check_repo "https://github.com/bitflags/bitflags.git" bitflags - check_repo "https://github.com/rust-lang/log.git" log - check_repo "https://github.com/rust-lang/mdBook.git" mdBook - check_repo "https://github.com/rust-lang/packed_simd.git" packed_simd - check_repo "https://github.com/rust-lang/rust-semverver.git" check_repo - check_repo "https://github.com/Stebalien/tempfile.git" tempfile - check_repo "https://github.com/rust-lang/futures-rs.git" futures-rs - check_repo "https://github.com/dtolnay/anyhow.git" anyhow - check_repo "https://github.com/dtolnay/thiserror.git" thiserror - check_repo "https://github.com/dtolnay/syn.git" syn - check_repo "https://github.com/serde-rs/serde.git" serde - check_repo "https://github.com/rust-lang/rustlings.git" rustlings - check_repo "https://github.com/rust-lang/rustup.git" rustup - check_repo "https://github.com/SergioBenitez/Rocket.git" Rocket - check_repo "https://github.com/rustls/rustls.git" rustls - check_repo "https://github.com/rust-lang/rust-bindgen.git" rust-bindgen - check_repo "https://github.com/hyperium/hyper.git" hyper - check_repo "https://github.com/actix/actix.git" actix - check_repo "https://github.com/denoland/deno.git" denoland_deno - - # cleanup temp dir - echo removing tmp_dir $tmp_dir - rm -rf $tmp_dir - - # figure out the exit code - for status in ${STATUSES[@]} - do - if [ $status -eq 1 ]; then - echo "formatting diff found 💔" - return 1 - fi - done - - echo "no diff found 😊" -} - -main diff --git a/docs/index.html b/docs/index.html index 5e588d1db54..13399be25ba 100644 --- a/docs/index.html +++ b/docs/index.html @@ -78,7 +78,7 @@

-
+
@@ -108,18 +108,18 @@