mirror of
https://github.com/sharkdp/fd.git
synced 2025-12-12 20:35:51 +01:00
build(msrv): Update msrv to 1.90.0
And upgrade to 2024 edition
This commit is contained in:
4
.github/workflows/CICD.yml
vendored
4
.github/workflows/CICD.yml
vendored
@@ -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
|
||||
|
||||
@@ -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
22
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{Result, anyhow};
|
||||
use nix::unistd::{Group, User};
|
||||
use std::fs;
|
||||
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
101
src/walk.rs
101
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));
|
||||
|
||||
Reference in New Issue
Block a user