Repository: sharkdp/fd
Pull request #1244 (2023-01-17 07:21:01)

update: Update to clap 4.1
This includes switching to the stable API for getting values grouped by occurrences, and updating tests to match the new error messages.


Patch:
diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml
index bdb72b8..5947061 100644
--- a/.github/workflows/CICD.yml
+++ b/.github/workflows/CICD.yml
@@ -1,7 +1,7 @@
 name: CICD
 
 env:
-  MIN_SUPPORTED_RUST_VERSION: "1.60.0"
+  MIN_SUPPORTED_RUST_VERSION: "1.64.0"
   CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
 
 on:
diff --git a/Cargo.lock b/Cargo.lock
index f264eb0..a9eb3de 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -101,14 +101,14 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.0.22"
+version = "4.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91b9970d7505127a162fdaa9b96428d28a479ba78c9ec7550a63a5d9863db682"
+checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2"
 dependencies = [
- "atty",
  "bitflags",
  "clap_derive",
  "clap_lex",
+ "is-terminal",
  "once_cell",
  "strsim",
  "termcolor",
@@ -126,9 +126,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.0.21"
+version = "4.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
+checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
 dependencies = [
  "heck",
  "proc-macro-error",
@@ -473,6 +473,28 @@ version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e6e481ccbe3dea62107216d0d1138bb8ad8e5e5c43009a098bd1990272c497b0"
 
+[[package]]
+name = "io-lifetimes"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
+dependencies = [
+ "libc",
+ "windows-sys 0.42.0",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
+dependencies = [
+ "hermit-abi 0.2.6",
+ "io-lifetimes 1.0.4",
+ "rustix 0.36.6",
+ "windows-sys 0.42.0",
+]
+
 [[package]]
 name = "jemalloc-sys"
 version = "0.5.2+5.3.0-patched"
@@ -530,6 +552,12 @@ version = "0.0.46"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
 
+[[package]]
+name = "linux-raw-sys"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
+
 [[package]]
 name = "log"
 version = "0.4.17"
@@ -718,9 +746,9 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.28"
+version = "0.6.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
+checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
 
 [[package]]
 name = "remove_dir_all"
@@ -739,12 +767,26 @@ checksum = "985947f9b6423159c4726323f373be0a21bdb514c5af06a849cb3d2dce2d01e8"
 dependencies = [
  "bitflags",
  "errno",
- "io-lifetimes",
+ "io-lifetimes 0.7.4",
  "libc",
- "linux-raw-sys",
+ "linux-raw-sys 0.0.46",
  "windows-sys 0.36.1",
 ]
 
+[[package]]
+name = "rustix"
+version = "0.36.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549"
+dependencies = [
+ "bitflags",
+ "errno",
+ "io-lifetimes 1.0.4",
+ "libc",
+ "linux-raw-sys 0.1.4",
+ "windows-sys 0.42.0",
+]
+
 [[package]]
 name = "same-file"
 version = "1.0.6"
@@ -806,7 +848,7 @@ version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8440c860cf79def6164e4a0a983bcc2305d82419177a0e0c71930d049e3ac5a1"
 dependencies = [
- "rustix",
+ "rustix 0.35.12",
  "windows-sys 0.36.1",
 ]
 
diff --git a/Cargo.toml b/Cargo.toml
index 7f258c9..d3db39c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,6 +18,7 @@ readme = "README.md"
 repository = "https://github.com/sharkdp/fd"
 version = "8.6.0"
 edition= "2021"
+rust-version = "1.64.0"
 
 [badges.appveyor]
 repository = "sharkdp/fd"
@@ -52,7 +53,7 @@ clap_complete = {version = "4.0.6", optional = true}
 faccess = "0.2.4"
 
 [dependencies.clap]
-version = "4.0.22"
+version = "4.1.1"
 features = ["suggestions", "color", "wrap_help", "cargo", "unstable-grouped", "derive"]
 
 [dependencies.chrono]
diff --git a/build.rs b/build.rs
index 224f2d3..5a4c372 100644
--- a/build.rs
+++ b/build.rs
@@ -1,5 +1,5 @@
 fn main() {
-    let min_version = "1.60";
+    let min_version = "1.64";
 
     match version_check::is_min_version(min_version) {
         Some(true) => {}
diff --git a/clippy.toml b/clippy.toml
index 16caf02..22fd4be 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -1,1 +1,1 @@
-msrv = "1.60.0"
+msrv = "1.64.0"
diff --git a/src/cli.rs b/src/cli.rs
index 8e97f1c..2e21bf6 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -738,11 +738,11 @@ pub struct Exec {
 impl clap::FromArgMatches for Exec {
     fn from_arg_matches(matches: &ArgMatches) -> clap::error::Result<Self> {
         let command = matches
-            .grouped_values_of("exec")
+            .get_occurrences::<String>("exec")
             .map(CommandSet::new)
             .or_else(|| {
                 matches
-                    .grouped_values_of("exec_batch")
+                    .get_occurrences::<String>("exec_batch")
                     .map(CommandSet::new_batch)
             })
             .transpose()
diff --git a/src/exec/mod.rs b/src/exec/mod.rs
index 167368b..17060b3 100644
--- a/src/exec/mod.rs
+++ b/src/exec/mod.rs
@@ -39,9 +39,10 @@ pub struct CommandSet {
 }
 
 impl CommandSet {
-    pub fn new<I, S>(input: I) -> Result<CommandSet>
+    pub fn new<I, T, S>(input: I) -> Result<CommandSet>
     where
-        I: IntoIterator<Item = Vec<S>>,
+        I: IntoIterator<Item = T>,
+        T: IntoIterator<Item = S>,
         S: AsRef<str>,
     {
         Ok(CommandSet {
@@ -53,9 +54,10 @@ impl CommandSet {
         })
     }
 
-    pub fn new_batch<I, S>(input: I) -> Result<CommandSet>
+    pub fn new_batch<I, T, S>(input: I) -> Result<CommandSet>
     where
-        I: IntoIterator<Item = Vec<S>>,
+        I: IntoIterator<Item = T>,
+        T: IntoIterator<Item = S>,
         S: AsRef<str>,
     {
         Ok(CommandSet {


Test patch:
diff --git a/tests/testenv/mod.rs b/tests/testenv/mod.rs
index 188559d..d4bfad2 100644
--- a/tests/testenv/mod.rs
+++ b/tests/testenv/mod.rs
@@ -20,9 +20,6 @@ pub struct TestEnv {
 
     /// Normalize each line by sorting the whitespace-separated words
     normalize_line: bool,
-
-    /// Temporary directory for storing test config (global ignore file)
-    config_dir: Option<TempDir>,
 }
 
 /// Create the working directory and the test files.
@@ -62,16 +59,6 @@ fn create_working_directory(
     Ok(temp_dir)
 }
 
-fn create_config_directory_with_global_ignore(ignore_file_content: &str) -> io::Result<TempDir> {
-    let config_dir = tempfile::Builder::new().prefix("fd-config").tempdir()?;
-    let fd_dir = config_dir.path().join("fd");
-    fs::create_dir(&fd_dir)?;
-    let mut ignore_file = fs::File::create(fd_dir.join("ignore"))?;
-    ignore_file.write_all(ignore_file_content.as_bytes())?;
-
-    Ok(config_dir)
-}
-
 /// Find the *fd* executable.
 fn find_fd_exe() -> PathBuf {
     // Tests exe is in target/debug/deps, the *fd* exe is in target/debug
@@ -163,7 +150,6 @@ impl TestEnv {
             temp_dir,
             fd_exe,
             normalize_line: false,
-            config_dir: None,
         }
     }
 
@@ -172,16 +158,6 @@ impl TestEnv {
             temp_dir: self.temp_dir,
             fd_exe: self.fd_exe,
             normalize_line: normalize,
-            config_dir: self.config_dir,
-        }
-    }
-
-    pub fn global_ignore_file(self, content: &str) -> TestEnv {
-        let config_dir =
-            create_config_directory_with_global_ignore(content).expect("config directory");
-        TestEnv {
-            config_dir: Some(config_dir),
-            ..self
         }
     }
 
@@ -230,8 +206,13 @@ impl TestEnv {
         path: P,
         args: &[&str],
     ) -> process::Output {
+        // Setup *fd* command.
+        let mut cmd = process::Command::new(&self.fd_exe);
+        cmd.current_dir(self.temp_dir.path().join(path));
+        cmd.arg("--no-global-ignore-file").args(args);
+
         // Run *fd*.
-        let output = self.run_command(path.as_ref(), args);
+        let output = cmd.output().expect("fd output");
 
         // Check for exit status.
         if !output.status.success() {
@@ -307,21 +288,6 @@ impl TestEnv {
         self.assert_error_subdirectory(".", args, Some(expected))
     }
 
-    fn run_command(&self, path: &Path, args: &[&str]) -> process::Output {
-        // Setup *fd* command.
-        let mut cmd = process::Command::new(&self.fd_exe);
-        cmd.current_dir(self.temp_dir.path().join(path));
-        if let Some(config_dir) = &self.config_dir {
-            cmd.env("XDG_CONFIG_HOME", config_dir.path());
-        } else {
-            cmd.arg("--no-global-ignore-file");
-        }
-        cmd.args(args);
-
-        // Run *fd*.
-        cmd.output().expect("fd output")
-    }
-
     /// Assert that calling *fd* in the specified path under the root working directory,
     /// and with the specified arguments produces an error with the expected message.
     fn assert_error_subdirectory<P: AsRef<Path>>(
@@ -330,7 +296,13 @@ impl TestEnv {
         args: &[&str],
         expected: Option<&str>,
     ) -> process::ExitStatus {
-        let output = self.run_command(path.as_ref(), args);
+        // Setup *fd* command.
+        let mut cmd = process::Command::new(&self.fd_exe);
+        cmd.current_dir(self.temp_dir.path().join(path));
+        cmd.arg("--no-global-ignore-file").args(args);
+
+        // Run *fd*.
+        let output = cmd.output().expect("fd output");
 
         if let Some(expected) = expected {
             // Normalize both expected and actual output.
diff --git a/tests/tests.rs b/tests/tests.rs
index 98fe9c8..20de3d8 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -879,47 +879,6 @@ fn test_no_ignore_aliases() {
     );
 }
 
-#[cfg(not(windows))]
-#[test]
-fn test_global_ignore() {
-    let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES).global_ignore_file("one");
-    te.assert_output(
-        &[],
-        "a.foo
-    e1 e2
-    symlink",
-    );
-}
-
-#[cfg(not(windows))]
-#[test_case("--unrestricted", ".hidden.foo
-a.foo
-fdignored.foo
-gitignored.foo
-one/b.foo
-one/two/c.foo
-one/two/C.Foo2
-one/two/three/d.foo
-one/two/three/directory_foo/"; "unrestricted")]
-#[test_case("--no-ignore", "a.foo
-fdignored.foo
-gitignored.foo
-one/b.foo
-one/two/c.foo
-one/two/C.Foo2
-one/two/three/d.foo
-one/two/three/directory_foo/"; "no-ignore")]
-#[test_case("--no-global-ignore-file", "a.foo
-one/b.foo
-one/two/c.foo
-one/two/C.Foo2
-one/two/three/d.foo
-one/two/three/directory_foo/"; "no-global-ignore-file")]
-fn test_no_global_ignore(flag: &str, expected_output: &str) {
-    let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES).global_ignore_file("one");
-    te.assert_output(&[flag, "foo"], expected_output);
-}
-
 /// Symlinks (--follow)
 #[test]
 fn test_follow() {
@@ -1749,18 +1708,26 @@ fn test_exec_batch() {
             \n\
             Usage: fd [OPTIONS] [pattern] [path]...\n\
             \n\
-            For more information try '--help'\n\
+            For more information, try '--help'.\n\
             ",
         );
 
         te.assert_failure_with_error(
             &["foo", "--exec-batch", "echo", "{/}", ";", "-x", "echo"],
-            "error: The argument '--exec-batch <cmd>...' cannot be used with '--exec <cmd>...'",
+            "error: the argument '--exec-batch <cmd>...' cannot be used with '--exec <cmd>...'\n\
+            \n\
+            Usage: fd --exec-batch <cmd>... <pattern> [path]...\n\
+            \n\
+            For more information, try '--help'.\n\
+            ",
         );
 
         te.assert_failure_with_error(
             &["foo", "--exec-batch"],
-            "error: The argument '--exec-batch <cmd>...' requires a value but none was supplied",
+            "error: a value is required for '--exec-batch <cmd>...' but none was supplied\n\
+            \n\
+            For more information, try '--help'.\n\
+            ",
         );
 
         te.assert_failure_with_error(
@@ -1769,7 +1736,7 @@ fn test_exec_batch() {
             \n\
             Usage: fd [OPTIONS] [pattern] [path]...\n\
             \n\
-            For more information try '--help'\n\
+            For more information, try '--help'.\n\
             ",
         );