build(msrv): Update msrv to 1.90.0

And upgrade to 2024 edition
This commit is contained in:
Thayne McCombs
2025-10-21 01:54:39 -06:00
parent da731c48d9
commit dbd3e3c14c
15 changed files with 129 additions and 121 deletions

View File

@@ -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

View File

@@ -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

22
Cargo.lock generated
View File

@@ -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"

View File

@@ -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"

View File

@@ -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;

View File

@@ -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;

View File

@@ -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};

View File

@@ -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 {

View File

@@ -1,4 +1,4 @@
use anyhow::{anyhow, Result};
use anyhow::{Result, anyhow};
use nix::unistd::{Group, User};
use std::fs;

View File

@@ -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)
);
}
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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<W: Write>(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 {

View File

@@ -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 {

View File

@@ -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));