diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 5848205f..74b3c508 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -116,9 +116,7 @@ jobs: uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.job.target }} - # On windows, for now build with 1.77.2, so that it works on windows 7. - # When we update the MSRV again, we'll need to revisit this, and probably drop support for Win7 - toolchain: "${{ contains(matrix.job.target, 'windows-') && '1.77.2' || 'stable' }}" + toolchain: "stable" - name: Install cross if: matrix.job.use-cross diff --git a/CHANGELOG.md b/CHANGELOG.md index 18e3f045..3bbb6328 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ ## Changes +- Minimum required rust version has been increased to 1.90.0. Notably, this means dropping fully support for intel Mac and Windows 7. + ## Other diff --git a/Cargo.lock b/Cargo.lock index 4f67c0c2..88c4c386 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" @@ -289,7 +289,6 @@ dependencies = [ "faccess", "filetime", "globset", - "home", "ignore", "jiff", "libc", @@ -355,11 +354,11 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -741,9 +740,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "utf8parse" @@ -807,15 +806,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.59.0" diff --git a/Cargo.toml b/Cargo.toml index 329a7835..6f5ea7a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,8 @@ name = "fd-find" readme = "README.md" repository = "https://github.com/sharkdp/fd" version = "10.3.0" -edition= "2021" -rust-version = "1.77.2" +edition= "2024" +rust-version = "1.90.0" [badges.appveyor] repository = "sharkdp/fd" @@ -35,7 +35,7 @@ aho-corasick = "1.1" nu-ansi-term = "0.50" argmax = "0.4.0" ignore = "0.4.24" -regex = "1.11.2" +regex = "1.12.2" regex-syntax = "0.8" ctrlc = "3.4" globset = "0.4" @@ -46,9 +46,6 @@ crossbeam-channel = "0.5.15" clap_complete = {version = "4.5.58", optional = true} faccess = "0.2.4" jiff = "0.2.14" -# For now, pin the `home` crate to less than 0.5.11, to ensure it works on older versions of rust -# TODO: when we upgrade past rust 1.85, remove this dependency -home = "=0.5.9" [dependencies.clap] version = "4.5.48" diff --git a/src/cli.rs b/src/cli.rs index 706d24bb..d5174689 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -4,8 +4,8 @@ use std::time::Duration; use anyhow::anyhow; use clap::{ - error::ErrorKind, value_parser, Arg, ArgAction, ArgGroup, ArgMatches, Command, Parser, - ValueEnum, + Arg, ArgAction, ArgGroup, ArgMatches, Command, Parser, ValueEnum, error::ErrorKind, + value_parser, }; #[cfg(feature = "completions")] use clap_complete::Shell; diff --git a/src/exec/job.rs b/src/exec/job.rs index d4702c47..55f1e88d 100644 --- a/src/exec/job.rs +++ b/src/exec/job.rs @@ -1,6 +1,6 @@ use crate::config::Config; use crate::error::print_error; -use crate::exit_codes::{merge_exitcodes, ExitCode}; +use crate::exit_codes::{ExitCode, merge_exitcodes}; use crate::walk::WorkerResult; use super::CommandSet; diff --git a/src/exec/mod.rs b/src/exec/mod.rs index c5000770..c22e0bd2 100644 --- a/src/exec/mod.rs +++ b/src/exec/mod.rs @@ -7,11 +7,11 @@ use std::iter; use std::path::{Path, PathBuf}; use std::process::Stdio; -use anyhow::{bail, Result}; +use anyhow::{Result, bail}; use argmax::Command; use crate::exec::command::OutputBuffer; -use crate::exit_codes::{merge_exitcodes, ExitCode}; +use crate::exit_codes::{ExitCode, merge_exitcodes}; use crate::fmt::{FormatTemplate, Token}; use self::command::{execute_commands, handle_cmd_error}; diff --git a/src/exit_codes.rs b/src/exit_codes.rs index c87d8c27..71f87280 100644 --- a/src/exit_codes.rs +++ b/src/exit_codes.rs @@ -1,7 +1,7 @@ use std::process; #[cfg(unix)] -use nix::sys::signal::{raise, signal, SigHandler, Signal}; +use nix::sys::signal::{SigHandler, Signal, raise, signal}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ExitCode { diff --git a/src/filter/owner.rs b/src/filter/owner.rs index 3ee38d7e..0f56fda7 100644 --- a/src/filter/owner.rs +++ b/src/filter/owner.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Result}; +use anyhow::{Result, anyhow}; use nix::unistd::{Group, User}; use std::fs; diff --git a/src/filter/time.rs b/src/filter/time.rs index dd4ad9bf..12e8f566 100644 --- a/src/filter/time.rs +++ b/src/filter/time.rs @@ -1,4 +1,4 @@ -use jiff::{civil::DateTime, tz::TimeZone, Span, Timestamp, Zoned}; +use jiff::{Span, Timestamp, Zoned, civil::DateTime, tz::TimeZone}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; @@ -114,16 +114,22 @@ mod tests { assert!(!TimeFilter::before("2min").unwrap().applies_to(&t1m_ago)); let t10s_before = "2010-10-10 10:10:00"; - assert!(!TimeFilter::before(t10s_before) - .unwrap() - .applies_to(&ref_time)); - assert!(TimeFilter::before(t10s_before) - .unwrap() - .applies_to(&t1m_ago)); + assert!( + !TimeFilter::before(t10s_before) + .unwrap() + .applies_to(&ref_time) + ); + assert!( + TimeFilter::before(t10s_before) + .unwrap() + .applies_to(&t1m_ago) + ); - assert!(TimeFilter::after(t10s_before) - .unwrap() - .applies_to(&ref_time)); + assert!( + TimeFilter::after(t10s_before) + .unwrap() + .applies_to(&ref_time) + ); assert!(!TimeFilter::after(t10s_before).unwrap().applies_to(&t1m_ago)); let same_day = "2010-10-10"; @@ -142,16 +148,22 @@ mod tests { ref_time = test_time.timestamp(); let t1m_ago = ref_time - Duration::from_secs(60); let t10s_before = "2010-10-10T10:10:00+00:00"; - assert!(!TimeFilter::before(t10s_before) - .unwrap() - .applies_to(&ref_time)); - assert!(TimeFilter::before(t10s_before) - .unwrap() - .applies_to(&t1m_ago)); + assert!( + !TimeFilter::before(t10s_before) + .unwrap() + .applies_to(&ref_time) + ); + assert!( + TimeFilter::before(t10s_before) + .unwrap() + .applies_to(&t1m_ago) + ); - assert!(TimeFilter::after(t10s_before) - .unwrap() - .applies_to(&ref_time)); + assert!( + TimeFilter::after(t10s_before) + .unwrap() + .applies_to(&ref_time) + ); assert!(!TimeFilter::after(t10s_before).unwrap().applies_to(&t1m_ago)); let ref_timestamp = 1707723412u64; // Mon Feb 12 07:36:52 UTC 2024 @@ -166,17 +178,25 @@ mod tests { let t1s_later = ref_time + Duration::from_secs(1); // Timestamp only supported via '@' prefix assert!(TimeFilter::before(&ref_timestamp.to_string()).is_none()); - assert!(TimeFilter::before(&format!("@{ref_timestamp}")) - .unwrap() - .applies_to(&t1m_ago)); - assert!(!TimeFilter::before(&format!("@{ref_timestamp}")) - .unwrap() - .applies_to(&t1s_later)); - assert!(!TimeFilter::after(&format!("@{ref_timestamp}")) - .unwrap() - .applies_to(&t1m_ago)); - assert!(TimeFilter::after(&format!("@{ref_timestamp}")) - .unwrap() - .applies_to(&t1s_later)); + assert!( + TimeFilter::before(&format!("@{ref_timestamp}")) + .unwrap() + .applies_to(&t1m_ago) + ); + assert!( + !TimeFilter::before(&format!("@{ref_timestamp}")) + .unwrap() + .applies_to(&t1s_later) + ); + assert!( + !TimeFilter::after(&format!("@{ref_timestamp}")) + .unwrap() + .applies_to(&t1m_ago) + ); + assert!( + TimeFilter::after(&format!("@{ref_timestamp}")) + .unwrap() + .applies_to(&t1s_later) + ); } } diff --git a/src/fmt/mod.rs b/src/fmt/mod.rs index 45e82fca..87ee4192 100644 --- a/src/fmt/mod.rs +++ b/src/fmt/mod.rs @@ -131,7 +131,7 @@ impl FormatTemplate { Placeholder => { s.push(Self::replace_separator(path.as_ref(), path_separator)) } - Text(ref string) => s.push(string), + Text(string) => s.push(string), } } s diff --git a/src/main.rs b/src/main.rs index 417fe8d5..fafb3b90 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ use std::io::IsTerminal; use std::path::Path; use std::sync::Arc; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{Context, Result, anyhow, bail}; use clap::{CommandFactory, Parser}; use globset::GlobBuilder; use lscolors::LsColors; diff --git a/src/output.rs b/src/output.rs index facebc77..91e9f021 100644 --- a/src/output.rs +++ b/src/output.rs @@ -15,11 +15,11 @@ fn replace_path_separator(path: &str, new_path_separator: &str) -> String { // TODO: this function is performance critical and can probably be optimized pub fn print_entry(stdout: &mut W, entry: &DirEntry, config: &Config) -> io::Result<()> { let mut has_hyperlink = false; - if config.hyperlink { - if let Some(url) = PathUrl::new(entry.path()) { - write!(stdout, "\x1B]8;;{url}\x1B\\")?; - has_hyperlink = true; - } + if config.hyperlink + && let Some(url) = PathUrl::new(entry.path()) + { + write!(stdout, "\x1B]8;;{url}\x1B\\")?; + has_hyperlink = true; } if let Some(ref format) = config.format { diff --git a/src/regex_helper.rs b/src/regex_helper.rs index b86bbefe..908ff10b 100644 --- a/src/regex_helper.rs +++ b/src/regex_helper.rs @@ -1,5 +1,5 @@ -use regex_syntax::hir::Hir; use regex_syntax::ParserBuilder; +use regex_syntax::hir::Hir; /// Determine if a regex pattern contains a literal uppercase character. pub fn pattern_has_uppercase_char(pattern: &str) -> bool { diff --git a/src/walk.rs b/src/walk.rs index a9a34c4d..27f295db 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -8,8 +8,8 @@ use std::sync::{Arc, Mutex, MutexGuard}; use std::thread; use std::time::{Duration, Instant}; -use anyhow::{anyhow, Result}; -use crossbeam_channel::{bounded, Receiver, RecvTimeoutError, SendError, Sender}; +use anyhow::{Result, anyhow}; +use crossbeam_channel::{Receiver, RecvTimeoutError, SendError, Sender, bounded}; use etcetera::BaseStrategy; use ignore::overrides::{Override, OverrideBuilder}; use ignore::{WalkBuilder, WalkParallel, WalkState}; @@ -19,7 +19,7 @@ use crate::config::Config; use crate::dir_entry::DirEntry; use crate::error::print_error; use crate::exec; -use crate::exit_codes::{merge_exitcodes, ExitCode}; +use crate::exit_codes::{ExitCode, merge_exitcodes}; use crate::filesystem; use crate::output; @@ -218,10 +218,10 @@ impl<'a, W: Write> ReceiverBuffer<'a, W> { } self.num_results += 1; - if let Some(max_results) = self.config.max_results { - if self.num_results >= max_results { - return self.stop(); - } + if let Some(max_results) = self.config.max_results + && self.num_results >= max_results + { + return self.stop(); } } WorkerResult::Error(err) => { @@ -250,11 +250,11 @@ impl<'a, W: Write> ReceiverBuffer<'a, W> { /// Output a path. fn print(&mut self, entry: &DirEntry) -> Result<(), ExitCode> { - if let Err(e) = output::print_entry(&mut self.stdout, entry, self.config) { - if e.kind() != ::std::io::ErrorKind::BrokenPipe { - print_error(format!("Could not write to output: {e}")); - return Err(ExitCode::GeneralError); - } + if let Err(e) = output::print_entry(&mut self.stdout, entry, self.config) + && e.kind() != ::std::io::ErrorKind::BrokenPipe + { + print_error(format!("Could not write to output: {e}")); + return Err(ExitCode::GeneralError); } if self.interrupt_flag.load(Ordering::Relaxed) { @@ -368,18 +368,18 @@ impl WorkerState { builder.add_custom_ignore_filename(".fdignore"); } - if config.read_global_ignore { - if let Ok(basedirs) = etcetera::choose_base_strategy() { - let global_ignore_file = basedirs.config_dir().join("fd").join("ignore"); - if global_ignore_file.is_file() { - let result = builder.add_ignore(global_ignore_file); - match result { - Some(ignore::Error::Partial(_)) => (), - Some(err) => { - print_error(format!("Malformed pattern in global ignore file. {err}.")); - } - None => (), + if config.read_global_ignore + && let Ok(basedirs) = etcetera::choose_base_strategy() + { + let global_ignore_file = basedirs.config_dir().join("fd").join("ignore"); + if global_ignore_file.is_file() { + let result = builder.add_ignore(global_ignore_file); + match result { + Some(ignore::Error::Partial(_)) => (), + Some(err) => { + print_error(format!("Malformed pattern in global ignore file. {err}.")); } + None => (), } } } @@ -447,11 +447,12 @@ impl WorkerState { let quit_flag = self.quit_flag.as_ref(); let mut limit = 0x100; - if let Some(cmd) = &config.command { - if !cmd.in_batch_mode() && config.threads > 1 { - // Evenly distribute work between multiple receivers - limit = 1; - } + if let Some(cmd) = &config.command + && !cmd.in_batch_mode() + && config.threads > 1 + { + // Evenly distribute work between multiple receivers + limit = 1; } let mut tx = BatchSender::new(tx.clone(), limit); @@ -486,21 +487,21 @@ impl WorkerState { })) { Ok(_) => WalkState::Continue, Err(_) => WalkState::Quit, - } + }; } }, Err(err) => { return match tx.send(WorkerResult::Error(err)) { Ok(_) => WalkState::Continue, Err(_) => WalkState::Quit, - } + }; } }; - if let Some(min_depth) = config.min_depth { - if entry.depth().map_or(true, |d| d < min_depth) { - return WalkState::Continue; - } + if let Some(min_depth) = config.min_depth + && entry.depth().is_none_or(|d| d < min_depth) + { + return WalkState::Continue; } // Check the name first, since it doesn't require metadata @@ -540,10 +541,10 @@ impl WorkerState { } // Filter out unwanted file types. - if let Some(ref file_types) = config.file_types { - if file_types.should_ignore(&entry) { - return WalkState::Continue; - } + if let Some(ref file_types) = config.file_types + && file_types.should_ignore(&entry) + { + return WalkState::Continue; } #[cfg(unix)] @@ -582,24 +583,24 @@ impl WorkerState { // Filter out unwanted modification times if !config.time_constraints.is_empty() { let mut matched = false; - if let Some(metadata) = entry.metadata() { - if let Ok(modified) = metadata.modified() { - matched = config - .time_constraints - .iter() - .all(|tf| tf.applies_to(&modified)); - } + if let Some(metadata) = entry.metadata() + && let Ok(modified) = metadata.modified() + { + matched = config + .time_constraints + .iter() + .all(|tf| tf.applies_to(&modified)); } if !matched { return WalkState::Continue; } } - if config.is_printing() { - if let Some(ls_colors) = &config.ls_colors { - // Compute colors in parallel - entry.style(ls_colors); - } + if config.is_printing() + && let Some(ls_colors) = &config.ls_colors + { + // Compute colors in parallel + entry.style(ls_colors); } let send_result = tx.send(WorkerResult::Entry(entry));