From a746e37dc7e087159ede20c9c887015d77ff6221 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Fri, 21 May 2021 18:20:05 -0400 Subject: [PATCH 01/39] truncate: add test for -r and -s options together Add a test for when the reference file is not found and both `-r` and `-s` options are given on the command-line. --- tests/by-util/test_truncate.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/by-util/test_truncate.rs b/tests/by-util/test_truncate.rs index 120982e3c..6323b058f 100644 --- a/tests/by-util/test_truncate.rs +++ b/tests/by-util/test_truncate.rs @@ -262,3 +262,11 @@ fn test_reference_file_not_found() { .fails() .stderr_contains("cannot stat 'a': No such file or directory"); } + +#[test] +fn test_reference_with_size_file_not_found() { + new_ucmd!() + .args(&["-r", "a", "-s", "+1", "b"]) + .fails() + .stderr_contains("cannot stat 'a': No such file or directory"); +} From 5eb2a5c3e1e72e7d01ce87eed55928f37b14d5ca Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Fri, 21 May 2021 18:23:50 -0400 Subject: [PATCH 02/39] truncate: remove read permissions from OpenOptions Remove "read" permissions from the `OpenOptions` when opening a new file just to truncate it. We will never read from the file, only write to it. (Specifically, we will only call `File::set_len()`.) --- src/uu/truncate/src/truncate.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/uu/truncate/src/truncate.rs b/src/uu/truncate/src/truncate.rs index 03b18723c..086e14858 100644 --- a/src/uu/truncate/src/truncate.rs +++ b/src/uu/truncate/src/truncate.rs @@ -189,12 +189,7 @@ fn truncate( }; for filename in &filenames { let path = Path::new(filename); - match OpenOptions::new() - .read(true) - .write(true) - .create(!no_create) - .open(path) - { + match OpenOptions::new().write(true).create(!no_create).open(path) { Ok(file) => { let fsize = match reference { Some(_) => refsize, From 544ae875753b050a5073278e8bcb8af893e31de0 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Fri, 21 May 2021 21:06:45 -0400 Subject: [PATCH 03/39] truncate: add parse_mode_and_size() helper func Add a helper function to contain the code for parsing the size and the modifier symbol, if any. This commit also changes the `TruncateMode` enum so that the parameter for each "mode" is stored along with the enumeration value. This is because the parameter has a different meaning in each mode. --- src/uu/truncate/src/truncate.rs | 136 ++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 51 deletions(-) diff --git a/src/uu/truncate/src/truncate.rs b/src/uu/truncate/src/truncate.rs index 086e14858..9df775300 100644 --- a/src/uu/truncate/src/truncate.rs +++ b/src/uu/truncate/src/truncate.rs @@ -15,16 +15,16 @@ use std::fs::{metadata, OpenOptions}; use std::io::ErrorKind; use std::path::Path; -#[derive(Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] enum TruncateMode { - Absolute, - Reference, - Extend, - Reduce, - AtMost, - AtLeast, - RoundDown, - RoundUp, + Reference(u64), + Absolute(u64), + Extend(u64), + Reduce(u64), + AtMost(u64), + AtLeast(u64), + RoundDown(u64), + RoundUp(u64), } static ABOUT: &str = "Shrink or extend the size of each file to the specified size."; @@ -133,46 +133,21 @@ fn truncate( size: Option, filenames: Vec, ) { - let (modsize, mode) = match size { - Some(size_string) => { - // Trim any whitespace. - let size_string = size_string.trim(); - - // Get the modifier character from the size string, if any. For - // example, if the argument is "+123", then the modifier is '+'. - let c = size_string.chars().next().unwrap(); - - let mode = match c { - '+' => TruncateMode::Extend, - '-' => TruncateMode::Reduce, - '<' => TruncateMode::AtMost, - '>' => TruncateMode::AtLeast, - '/' => TruncateMode::RoundDown, - '%' => TruncateMode::RoundUp, - _ => TruncateMode::Absolute, /* assume that the size is just a number */ - }; - - // If there was a modifier character, strip it. - let size_string = match mode { - TruncateMode::Absolute => size_string, - _ => &size_string[1..], - }; - let num_bytes = match parse_size(size_string) { - Ok(b) => b, - Err(_) => crash!(1, "Invalid number: ‘{}’", size_string), - }; - (num_bytes, mode) - } - None => (0, TruncateMode::Reference), + let mode = match size { + Some(size_string) => match parse_mode_and_size(&size_string) { + Ok(m) => m, + Err(_) => crash!(1, "Invalid number: ‘{}’", size_string), + }, + None => TruncateMode::Reference(0), }; let refsize = match reference { Some(ref rfilename) => { match mode { // Only Some modes work with a reference - TruncateMode::Reference => (), //No --size was given - TruncateMode::Extend => (), - TruncateMode::Reduce => (), + TruncateMode::Reference(_) => (), //No --size was given + TruncateMode::Extend(_) => (), + TruncateMode::Reduce(_) => (), _ => crash!(1, "you must specify a relative ‘--size’ with ‘--reference’"), }; match metadata(rfilename) { @@ -202,14 +177,14 @@ fn truncate( }, }; let tsize: u64 = match mode { - TruncateMode::Absolute => modsize, - TruncateMode::Reference => fsize, - TruncateMode::Extend => fsize + modsize, - TruncateMode::Reduce => fsize - modsize, - TruncateMode::AtMost => fsize.min(modsize), - TruncateMode::AtLeast => fsize.max(modsize), - TruncateMode::RoundDown => fsize - fsize % modsize, - TruncateMode::RoundUp => fsize + fsize % modsize, + TruncateMode::Absolute(modsize) => modsize, + TruncateMode::Reference(_) => fsize, + TruncateMode::Extend(modsize) => fsize + modsize, + TruncateMode::Reduce(modsize) => fsize - modsize, + TruncateMode::AtMost(modsize) => fsize.min(modsize), + TruncateMode::AtLeast(modsize) => fsize.max(modsize), + TruncateMode::RoundDown(modsize) => fsize - fsize % modsize, + TruncateMode::RoundUp(modsize) => fsize + fsize % modsize, }; match file.set_len(tsize) { Ok(_) => {} @@ -221,6 +196,52 @@ fn truncate( } } +/// Decide whether a character is one of the size modifiers, like '+' or '<'. +fn is_modifier(c: char) -> bool { + c == '+' || c == '-' || c == '<' || c == '>' || c == '/' || c == '%' +} + +/// Parse a size string with optional modifier symbol as its first character. +/// +/// A size string is as described in [`parse_size`]. The first character +/// of `size_string` might be a modifier symbol, like `'+'` or +/// `'<'`. The first element of the pair returned by this function +/// indicates which modifier symbol was present, or +/// [`TruncateMode::Absolute`] if none. +/// +/// # Panics +/// +/// If `size_string` is empty, or if no number could be parsed from the +/// given string (for example, if the string were `"abc"`). +/// +/// # Examples +/// +/// ```rust,ignore +/// assert_eq!(parse_mode_and_size("+123"), (TruncateMode::Extend, 123)); +/// ``` +fn parse_mode_and_size(size_string: &str) -> Result { + // Trim any whitespace. + let size_string = size_string.trim(); + + // Get the modifier character from the size string, if any. For + // example, if the argument is "+123", then the modifier is '+'. + let c = size_string.chars().next().unwrap(); + let size_string = if is_modifier(c) { + &size_string[1..] + } else { + size_string + }; + parse_size(size_string).map(match c { + '+' => TruncateMode::Extend, + '-' => TruncateMode::Reduce, + '<' => TruncateMode::AtMost, + '>' => TruncateMode::AtLeast, + '/' => TruncateMode::RoundDown, + '%' => TruncateMode::RoundUp, + _ => TruncateMode::Absolute, + }) +} + /// Parse a size string into a number of bytes. /// /// A size string comprises an integer and an optional unit. The unit @@ -280,7 +301,9 @@ fn parse_size(size: &str) -> Result { #[cfg(test)] mod tests { + use crate::parse_mode_and_size; use crate::parse_size; + use crate::TruncateMode; #[test] fn test_parse_size_zero() { @@ -306,4 +329,15 @@ mod tests { assert_eq!(parse_size("123M").unwrap(), 123 * 1024 * 1024); assert_eq!(parse_size("123MB").unwrap(), 123 * 1000 * 1000); } + + #[test] + fn test_parse_mode_and_size() { + assert_eq!(parse_mode_and_size("10"), Ok(TruncateMode::Absolute(10))); + assert_eq!(parse_mode_and_size("+10"), Ok(TruncateMode::Extend(10))); + assert_eq!(parse_mode_and_size("-10"), Ok(TruncateMode::Reduce(10))); + assert_eq!(parse_mode_and_size("<10"), Ok(TruncateMode::AtMost(10))); + assert_eq!(parse_mode_and_size(">10"), Ok(TruncateMode::AtLeast(10))); + assert_eq!(parse_mode_and_size("/10"), Ok(TruncateMode::RoundDown(10))); + assert_eq!(parse_mode_and_size("%10"), Ok(TruncateMode::RoundUp(10))); + } } From c6d4d0c07d1f1ed5d6dbe58ca0eda5e9c939b2c2 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Fri, 21 May 2021 21:09:33 -0400 Subject: [PATCH 04/39] truncate: create TruncateMode::to_size() method Create a method that computes the final target size in bytes for the file to truncate, given the reference file size and the parameter to the `TruncateMode`. --- src/uu/truncate/src/truncate.rs | 37 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/uu/truncate/src/truncate.rs b/src/uu/truncate/src/truncate.rs index 9df775300..c0f078458 100644 --- a/src/uu/truncate/src/truncate.rs +++ b/src/uu/truncate/src/truncate.rs @@ -27,6 +27,32 @@ enum TruncateMode { RoundUp(u64), } +impl TruncateMode { + /// Compute a target size in bytes for this truncate mode. + /// + /// `fsize` is the size of the reference file, in bytes. + /// + /// # Examples + /// + /// ```rust,ignore + /// let mode = TruncateMode::Extend(5); + /// let fsize = 10; + /// assert_eq!(mode.to_size(fsize), 15); + /// ``` + fn to_size(&self, fsize: u64) -> u64 { + match self { + TruncateMode::Absolute(modsize) => *modsize, + TruncateMode::Reference(_) => fsize, + TruncateMode::Extend(modsize) => fsize + modsize, + TruncateMode::Reduce(modsize) => fsize - modsize, + TruncateMode::AtMost(modsize) => fsize.min(*modsize), + TruncateMode::AtLeast(modsize) => fsize.max(*modsize), + TruncateMode::RoundDown(modsize) => fsize - fsize % modsize, + TruncateMode::RoundUp(modsize) => fsize + fsize % modsize, + } + } +} + static ABOUT: &str = "Shrink or extend the size of each file to the specified size."; static VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -176,16 +202,7 @@ fn truncate( } }, }; - let tsize: u64 = match mode { - TruncateMode::Absolute(modsize) => modsize, - TruncateMode::Reference(_) => fsize, - TruncateMode::Extend(modsize) => fsize + modsize, - TruncateMode::Reduce(modsize) => fsize - modsize, - TruncateMode::AtMost(modsize) => fsize.min(modsize), - TruncateMode::AtLeast(modsize) => fsize.max(modsize), - TruncateMode::RoundDown(modsize) => fsize - fsize % modsize, - TruncateMode::RoundUp(modsize) => fsize + fsize % modsize, - }; + let tsize = mode.to_size(fsize); match file.set_len(tsize) { Ok(_) => {} Err(f) => crash!(1, "{}", f.to_string()), From 1f1cd3d966cd4317c2eec8e8dfdcfb350f79fcf4 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Fri, 21 May 2021 21:12:13 -0400 Subject: [PATCH 05/39] truncate: re-organize into one func for each mode Reorganize the code in `truncate.rs` into three distinct functions representing the three modes of operation of the `truncate` program. The three modes are - `truncate -r RFILE FILE`, which sets the length of `FILE` to match the length of `RFILE`, - `truncate -r RFILE -s NUM FILE`, which sets the length of `FILE` relative to the given `RFILE`, - `truncate -s NUM FILE`, which sets the length of `FILE` either absolutely or relative to its curent length. This organization of the code makes it more concise and easier to follow. --- src/uu/truncate/src/truncate.rs | 196 ++++++++++++++++++++++---------- 1 file changed, 139 insertions(+), 57 deletions(-) diff --git a/src/uu/truncate/src/truncate.rs b/src/uu/truncate/src/truncate.rs index c0f078458..3a6077b3c 100644 --- a/src/uu/truncate/src/truncate.rs +++ b/src/uu/truncate/src/truncate.rs @@ -17,7 +17,6 @@ use std::path::Path; #[derive(Debug, Eq, PartialEq)] enum TruncateMode { - Reference(u64), Absolute(u64), Extend(u64), Reduce(u64), @@ -42,7 +41,6 @@ impl TruncateMode { fn to_size(&self, fsize: u64) -> u64 { match self { TruncateMode::Absolute(modsize) => *modsize, - TruncateMode::Reference(_) => fsize, TruncateMode::Extend(modsize) => fsize + modsize, TruncateMode::Reduce(modsize) => fsize - modsize, TruncateMode::AtMost(modsize) => fsize.min(*modsize), @@ -142,74 +140,158 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let no_create = matches.is_present(options::NO_CREATE); let reference = matches.value_of(options::REFERENCE).map(String::from); let size = matches.value_of(options::SIZE).map(String::from); - if reference.is_none() && size.is_none() { - crash!(1, "you must specify either --reference or --size"); - } else { - truncate(no_create, io_blocks, reference, size, files); + if let Err(e) = truncate(no_create, io_blocks, reference, size, files) { + match e.kind() { + ErrorKind::NotFound => { + // TODO Improve error-handling so that the error + // returned by `truncate()` provides the necessary + // parameter for formatting the error message. + let reference = matches.value_of(options::REFERENCE).map(String::from); + crash!( + 1, + "cannot stat '{}': No such file or directory", + reference.unwrap() + ); + } + _ => crash!(1, "{}", e.to_string()), + } } } 0 } +/// Truncate the named file to the specified size. +/// +/// If `create` is true, then the file will be created if it does not +/// already exist. If `size` is larger than the number of bytes in the +/// file, then the file will be padded with zeros. If `size` is smaller +/// than the number of bytes in the file, then the file will be +/// truncated and any bytes beyond `size` will be lost. +/// +/// # Errors +/// +/// If the file could not be opened, or there was a problem setting the +/// size of the file. +fn file_truncate(filename: &str, create: bool, size: u64) -> std::io::Result<()> { + let path = Path::new(filename); + let f = OpenOptions::new().write(true).create(create).open(path)?; + f.set_len(size) +} + +/// Truncate files to a size relative to a given file. +/// +/// `rfilename` is the name of the reference file. +/// +/// `size_string` gives the size relative to the reference file to which +/// to set the target files. For example, "+3K" means "set each file to +/// be three kilobytes larger than the size of the reference file". +/// +/// If `create` is true, then each file will be created if it does not +/// already exist. +/// +/// # Errors +/// +/// If the any file could not be opened, or there was a problem setting +/// the size of at least one file. +fn truncate_reference_and_size( + rfilename: &str, + size_string: &str, + filenames: Vec, + create: bool, +) -> std::io::Result<()> { + let mode = match parse_mode_and_size(size_string) { + Ok(m) => match m { + TruncateMode::Absolute(_) => { + crash!(1, "you must specify a relative ‘--size’ with ‘--reference’") + } + _ => m, + }, + Err(_) => crash!(1, "Invalid number: ‘{}’", size_string), + }; + let fsize = metadata(rfilename)?.len(); + let tsize = mode.to_size(fsize); + for filename in &filenames { + file_truncate(filename, create, tsize)?; + } + Ok(()) +} + +/// Truncate files to match the size of a given reference file. +/// +/// `rfilename` is the name of the reference file. +/// +/// If `create` is true, then each file will be created if it does not +/// already exist. +/// +/// # Errors +/// +/// If the any file could not be opened, or there was a problem setting +/// the size of at least one file. +fn truncate_reference_file_only( + rfilename: &str, + filenames: Vec, + create: bool, +) -> std::io::Result<()> { + let tsize = metadata(rfilename)?.len(); + for filename in &filenames { + file_truncate(filename, create, tsize)?; + } + Ok(()) +} + +/// Truncate files to a specified size. +/// +/// `size_string` gives either an absolute size or a relative size. A +/// relative size adjusts the size of each file relative to its current +/// size. For example, "3K" means "set each file to be three kilobytes" +/// whereas "+3K" means "set each file to be three kilobytes larger than +/// its current size". +/// +/// If `create` is true, then each file will be created if it does not +/// already exist. +/// +/// # Errors +/// +/// If the any file could not be opened, or there was a problem setting +/// the size of at least one file. +fn truncate_size_only( + size_string: &str, + filenames: Vec, + create: bool, +) -> std::io::Result<()> { + let mode = match parse_mode_and_size(size_string) { + Ok(m) => m, + Err(_) => crash!(1, "Invalid number: ‘{}’", size_string), + }; + for filename in &filenames { + let fsize = metadata(filename).map(|m| m.len()).unwrap_or(0); + let tsize = mode.to_size(fsize); + file_truncate(filename, create, tsize)?; + } + Ok(()) +} + fn truncate( no_create: bool, _: bool, reference: Option, size: Option, filenames: Vec, -) { - let mode = match size { - Some(size_string) => match parse_mode_and_size(&size_string) { - Ok(m) => m, - Err(_) => crash!(1, "Invalid number: ‘{}’", size_string), - }, - None => TruncateMode::Reference(0), - }; - - let refsize = match reference { - Some(ref rfilename) => { - match mode { - // Only Some modes work with a reference - TruncateMode::Reference(_) => (), //No --size was given - TruncateMode::Extend(_) => (), - TruncateMode::Reduce(_) => (), - _ => crash!(1, "you must specify a relative ‘--size’ with ‘--reference’"), - }; - match metadata(rfilename) { - Ok(meta) => meta.len(), - Err(f) => match f.kind() { - ErrorKind::NotFound => { - crash!(1, "cannot stat '{}': No such file or directory", rfilename) - } - _ => crash!(1, "{}", f.to_string()), - }, - } - } - None => 0, - }; - for filename in &filenames { - let path = Path::new(filename); - match OpenOptions::new().write(true).create(!no_create).open(path) { - Ok(file) => { - let fsize = match reference { - Some(_) => refsize, - None => match metadata(filename) { - Ok(meta) => meta.len(), - Err(f) => { - show_warning!("{}", f.to_string()); - continue; - } - }, - }; - let tsize = mode.to_size(fsize); - match file.set_len(tsize) { - Ok(_) => {} - Err(f) => crash!(1, "{}", f.to_string()), - }; - } - Err(f) => crash!(1, "{}", f.to_string()), +) -> std::io::Result<()> { + let create = !no_create; + // There are four possibilities + // - reference file given and size given, + // - reference file given but no size given, + // - no reference file given but size given, + // - no reference file given and no size given, + match (reference, size) { + (Some(rfilename), Some(size_string)) => { + truncate_reference_and_size(&rfilename, &size_string, filenames, create) } + (Some(rfilename), None) => truncate_reference_file_only(&rfilename, filenames, create), + (None, Some(size_string)) => truncate_size_only(&size_string, filenames, create), + (None, None) => crash!(1, "you must specify either --reference or --size"), } } From 64598d9e26fd39820a03dc793273636928c03d4c Mon Sep 17 00:00:00 2001 From: Mikadore Date: Wed, 26 May 2021 22:15:28 +0200 Subject: [PATCH 06/39] Closing #1916 --- tests/common/util.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/common/util.rs b/tests/common/util.rs index 611baadd4..d1c6259b6 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -62,54 +62,54 @@ pub struct CmdResult { /// see [`success`] success: bool, /// captured standard output after running the Command - stdout: String, + stdout: Vec, /// captured standard error after running the Command - stderr: String, + stderr: Vec, } impl CmdResult { /// Returns a reference to the program's standard output as a slice of bytes pub fn stdout(&self) -> &[u8] { - &self.stdout.as_bytes() + &self.stdout } /// Returns the program's standard output as a string slice pub fn stdout_str(&self) -> &str { - &self.stdout + std::str::from_utf8(&self.stdout).unwrap() } /// Returns the program's standard output as a string /// consumes self pub fn stdout_move_str(self) -> String { - self.stdout + String::from_utf8(self.stdout).unwrap() } /// Returns the program's standard output as a vec of bytes /// consumes self pub fn stdout_move_bytes(self) -> Vec { - Vec::from(self.stdout) + self.stdout } /// Returns a reference to the program's standard error as a slice of bytes pub fn stderr(&self) -> &[u8] { - &self.stderr.as_bytes() + &self.stderr } /// Returns the program's standard error as a string slice pub fn stderr_str(&self) -> &str { - &self.stderr + std::str::from_utf8(&self.stderr).unwrap() } /// Returns the program's standard error as a string /// consumes self pub fn stderr_move_str(self) -> String { - self.stderr + String::from_utf8(self.stderr).unwrap() } /// Returns the program's standard error as a vec of bytes /// consumes self pub fn stderr_move_bytes(self) -> Vec { - Vec::from(self.stderr) + self.stderr } /// Returns the program's exit code @@ -202,21 +202,21 @@ impl CmdResult { /// passed in value, trailing whitespace are kept to force strict comparison (#1235) /// stdout_only is a better choice unless stderr may or will be non-empty pub fn stdout_is>(&self, msg: T) -> &CmdResult { - assert_eq!(self.stdout, String::from(msg.as_ref())); + assert_eq!(self.stdout_str(), String::from(msg.as_ref())); self } /// Like `stdout_is` but newlines are normalized to `\n`. pub fn normalized_newlines_stdout_is>(&self, msg: T) -> &CmdResult { let msg = msg.as_ref().replace("\r\n", "\n"); - assert_eq!(self.stdout.replace("\r\n", "\n"), msg); + assert_eq!(self.stdout_str().replace("\r\n", "\n"), msg); self } /// asserts that the command resulted in stdout stream output, /// whose bytes equal those of the passed in slice pub fn stdout_is_bytes>(&self, msg: T) -> &CmdResult { - assert_eq!(self.stdout.as_bytes(), msg.as_ref()); + assert_eq!(self.stdout, msg.as_ref()); self } @@ -231,7 +231,7 @@ impl CmdResult { /// stderr_only is a better choice unless stdout may or will be non-empty pub fn stderr_is>(&self, msg: T) -> &CmdResult { assert_eq!( - self.stderr.trim_end(), + self.stderr_str().trim_end(), String::from(msg.as_ref()).trim_end() ); self @@ -240,7 +240,7 @@ impl CmdResult { /// asserts that the command resulted in stderr stream output, /// whose bytes equal those of the passed in slice pub fn stderr_is_bytes>(&self, msg: T) -> &CmdResult { - assert_eq!(self.stderr.as_bytes(), msg.as_ref()); + assert_eq!(self.stderr, msg.as_ref()); self } @@ -874,8 +874,8 @@ impl UCommand { tmpd: self.tmpd.clone(), code: prog.status.code(), success: prog.status.success(), - stdout: from_utf8(&prog.stdout).unwrap().to_string(), - stderr: from_utf8(&prog.stderr).unwrap().to_string(), + stdout: prog.stdout, + stderr: prog.stderr } } From 5e1d52d4be95d0f8cd09019dbc9f8f1196f002b6 Mon Sep 17 00:00:00 2001 From: Mikadore Date: Wed, 26 May 2021 22:20:16 +0200 Subject: [PATCH 07/39] cargo-fmt :DDD --- tests/common/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/common/util.rs b/tests/common/util.rs index d1c6259b6..94d0df851 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -875,7 +875,7 @@ impl UCommand { code: prog.status.code(), success: prog.status.success(), stdout: prog.stdout, - stderr: prog.stderr + stderr: prog.stderr, } } From 29f6dd1f3583d954be7921dac9f3fbf8456f7ae5 Mon Sep 17 00:00:00 2001 From: Mikadore Date: Thu, 27 May 2021 16:55:14 +0200 Subject: [PATCH 08/39] Fixed warning --- tests/common/util.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/common/util.rs b/tests/common/util.rs index 94d0df851..ba4eed317 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -16,7 +16,6 @@ use std::os::windows::fs::{symlink_dir, symlink_file}; use std::path::{Path, PathBuf}; use std::process::{Child, Command, Stdio}; use std::rc::Rc; -use std::str::from_utf8; use std::thread::sleep; use std::time::Duration; use tempfile::TempDir; From 263b1225404c9e1bef299433093df761a13b1cb3 Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Fri, 28 May 2021 17:48:48 +0200 Subject: [PATCH 09/39] maint: use the matches! macro when possible --- src/uu/csplit/src/csplit.rs | 7 +------ src/uu/expr/src/tokens.rs | 7 +------ src/uu/fmt/src/parasplit.rs | 16 ++++------------ src/uu/hashsum/src/hashsum.rs | 25 +++++++++++++++++-------- src/uu/od/src/parse_formats.rs | 7 +------ src/uu/rm/src/rm.rs | 7 +------ src/uu/sort/src/numeric_str_cmp.rs | 8 ++++---- src/uu/sort/src/sort.rs | 11 +++++------ src/uu/test/src/parser.rs | 8 +------- 9 files changed, 35 insertions(+), 61 deletions(-) diff --git a/src/uu/csplit/src/csplit.rs b/src/uu/csplit/src/csplit.rs index 9d2f81f43..f67f4958f 100644 --- a/src/uu/csplit/src/csplit.rs +++ b/src/uu/csplit/src/csplit.rs @@ -124,12 +124,7 @@ where // split the file based on patterns for pattern in patterns.into_iter() { let pattern_as_str = pattern.to_string(); - #[allow(clippy::match_like_matches_macro)] - let is_skip = if let patterns::Pattern::SkipToMatch(_, _, _) = pattern { - true - } else { - false - }; + let is_skip = matches!(pattern, patterns::Pattern::SkipToMatch(_, _, _)); match pattern { patterns::Pattern::UpToLine(n, ex) => { let mut up_to_line = n; diff --git a/src/uu/expr/src/tokens.rs b/src/uu/expr/src/tokens.rs index b65b0d482..6056e4ba1 100644 --- a/src/uu/expr/src/tokens.rs +++ b/src/uu/expr/src/tokens.rs @@ -63,12 +63,7 @@ impl Token { } } fn is_a_close_paren(&self) -> bool { - #[allow(clippy::match_like_matches_macro)] - // `matches!(...)` macro not stabilized until rust v1.42 - match *self { - Token::ParClose => true, - _ => false, - } + matches!(*self, Token::ParClose) } } diff --git a/src/uu/fmt/src/parasplit.rs b/src/uu/fmt/src/parasplit.rs index 950b3f66d..71b5f62ec 100644 --- a/src/uu/fmt/src/parasplit.rs +++ b/src/uu/fmt/src/parasplit.rs @@ -264,12 +264,9 @@ impl<'a> ParagraphStream<'a> { return false; } - #[allow(clippy::match_like_matches_macro)] - // `matches!(...)` macro not stabilized until rust v1.42 - l_slice[..colon_posn].chars().all(|x| match x as usize { - y if !(33..=126).contains(&y) => false, - _ => true, - }) + l_slice[..colon_posn] + .chars() + .all(|x| !matches!(x as usize, y if !(33..=126).contains(&y))) } } } @@ -541,12 +538,7 @@ impl<'a> WordSplit<'a> { } fn is_punctuation(c: char) -> bool { - #[allow(clippy::match_like_matches_macro)] - // `matches!(...)` macro not stabilized until rust v1.42 - match c { - '!' | '.' | '?' => true, - _ => false, - } + matches!(c, '!' | '.' | '?') } } diff --git a/src/uu/hashsum/src/hashsum.rs b/src/uu/hashsum/src/hashsum.rs index 2e31ddd25..b1ba3c217 100644 --- a/src/uu/hashsum/src/hashsum.rs +++ b/src/uu/hashsum/src/hashsum.rs @@ -51,14 +51,23 @@ struct Options { } fn is_custom_binary(program: &str) -> bool { - #[allow(clippy::match_like_matches_macro)] - // `matches!(...)` macro not stabilized until rust v1.42 - match program { - "md5sum" | "sha1sum" | "sha224sum" | "sha256sum" | "sha384sum" | "sha512sum" - | "sha3sum" | "sha3-224sum" | "sha3-256sum" | "sha3-384sum" | "sha3-512sum" - | "shake128sum" | "shake256sum" | "b2sum" => true, - _ => false, - } + matches!( + program, + "md5sum" + | "sha1sum" + | "sha224sum" + | "sha256sum" + | "sha384sum" + | "sha512sum" + | "sha3sum" + | "sha3-224sum" + | "sha3-256sum" + | "sha3-384sum" + | "sha3-512sum" + | "shake128sum" + | "shake256sum" + | "b2sum" + ) } #[allow(clippy::cognitive_complexity)] diff --git a/src/uu/od/src/parse_formats.rs b/src/uu/od/src/parse_formats.rs index 8b32d648c..abf05ea18 100644 --- a/src/uu/od/src/parse_formats.rs +++ b/src/uu/od/src/parse_formats.rs @@ -85,12 +85,7 @@ fn od_format_type(type_char: FormatType, byte_size: u8) -> Option bool { - #[allow(clippy::match_like_matches_macro)] - // `matches!(...)` macro not stabilized until rust v1.42 - match ch { - 'A' | 'j' | 'N' | 'S' | 'w' => true, - _ => false, - } + matches!(ch, 'A' | 'j' | 'N' | 'S' | 'w') } /// Parses format flags from command line diff --git a/src/uu/rm/src/rm.rs b/src/uu/rm/src/rm.rs index 94626b4e7..8010988bb 100644 --- a/src/uu/rm/src/rm.rs +++ b/src/uu/rm/src/rm.rs @@ -386,13 +386,8 @@ fn prompt(msg: &str) -> bool { let stdin = stdin(); let mut stdin = stdin.lock(); - #[allow(clippy::match_like_matches_macro)] - // `matches!(...)` macro not stabilized until rust v1.42 match stdin.read_until(b'\n', &mut buf) { - Ok(x) if x > 0 => match buf[0] { - b'y' | b'Y' => true, - _ => false, - }, + Ok(x) if x > 0 => matches!(buf[0], b'y' | b'Y'), _ => false, } } diff --git a/src/uu/sort/src/numeric_str_cmp.rs b/src/uu/sort/src/numeric_str_cmp.rs index f8666b701..76dc81aeb 100644 --- a/src/uu/sort/src/numeric_str_cmp.rs +++ b/src/uu/sort/src/numeric_str_cmp.rs @@ -68,10 +68,10 @@ impl NumInfo { } first_char = false; - if parse_settings - .thousands_separator - .map_or(false, |c| c == char) - { + if matches!( + parse_settings.thousands_separator, + Some(c) if c == char, + ) { continue; } diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 6d79e80fb..cc391af00 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -583,11 +583,10 @@ impl FieldSelector { is_default_selection: from.field == 1 && from.char == 1 && to.is_none() - // TODO: Once our MinRustV is 1.42 or higher, change this to the matches! macro - && match settings.mode { - SortMode::Numeric | SortMode::GeneralNumeric | SortMode::HumanNumeric => false, - _ => true, - }, + && !matches!( + settings.mode, + SortMode::Numeric | SortMode::GeneralNumeric | SortMode::HumanNumeric, + ), needs_tokens: from.field != 1 || from.char == 0 || to.is_some(), from, to, @@ -650,7 +649,7 @@ impl FieldSelector { tokens: Option<&[Field]>, position: &KeyPosition, ) -> Resolution { - if tokens.map_or(false, |fields| fields.len() < position.field) { + if matches!(tokens, Some(tokens) if tokens.len() < position.field) { Resolution::TooHigh } else if position.char == 0 { let end = tokens.unwrap()[position.field - 1].end; diff --git a/src/uu/test/src/parser.rs b/src/uu/test/src/parser.rs index aa44bc5f2..0fcb25bd5 100644 --- a/src/uu/test/src/parser.rs +++ b/src/uu/test/src/parser.rs @@ -121,13 +121,7 @@ impl Parser { /// Test if the next token in the stream is a BOOLOP (-a or -o), without /// removing the token from the stream. fn peek_is_boolop(&mut self) -> bool { - // TODO: change to `matches!(self.peek(), Symbol::BoolOp(_))` once MSRV is 1.42 - // #[allow(clippy::match_like_matches_macro)] // needs MSRV 1.43 - if let Symbol::BoolOp(_) = self.peek() { - true - } else { - false - } + matches!(self.peek(), Symbol::BoolOp(_)) } /// Parse an expression. From 59a42f1254a1c8f6f328f4b1ec9f6b4456950ff8 Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Fri, 28 May 2021 17:49:11 +0200 Subject: [PATCH 10/39] maint: format recent changes --- src/uu/mktemp/src/mktemp.rs | 15 ++++----------- src/uu/sort/src/ext_sort.rs | 7 ++++++- src/uu/stdbuf/src/stdbuf.rs | 3 +-- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index d66dd3d57..f6c244bf2 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -210,21 +210,14 @@ pub fn dry_exec(mut tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str) -> 0 } -fn exec( - dir: PathBuf, - prefix: &str, - rand: usize, - suffix: &str, - make_dir: bool, - quiet: bool, -) -> i32 { +fn exec(dir: PathBuf, prefix: &str, rand: usize, suffix: &str, make_dir: bool, quiet: bool) -> i32 { let res = if make_dir { let tmpdir = Builder::new() .prefix(prefix) .rand_bytes(rand) .suffix(suffix) .tempdir_in(&dir); - + // `into_path` consumes the TempDir without removing it tmpdir.map(|d| d.into_path().to_string_lossy().to_string()) } else { @@ -233,7 +226,7 @@ fn exec( .rand_bytes(rand) .suffix(suffix) .tempfile_in(&dir); - + match tmpfile { Ok(f) => { // `keep` ensures that the file is not deleted @@ -245,7 +238,7 @@ fn exec( } } } - Err(x) => Err(x) + Err(x) => Err(x), } }; diff --git a/src/uu/sort/src/ext_sort.rs b/src/uu/sort/src/ext_sort.rs index 23a55aad0..9b1845efa 100644 --- a/src/uu/sort/src/ext_sort.rs +++ b/src/uu/sort/src/ext_sort.rs @@ -34,7 +34,12 @@ const MIN_BUFFER_SIZE: usize = 8_000; /// Sort files by using auxiliary files for storing intermediate chunks (if needed), and output the result. pub fn ext_sort(files: &mut impl Iterator>, settings: &GlobalSettings) { - let tmp_dir = crash_if_err!(1, tempfile::Builder::new().prefix("uutils_sort").tempdir_in(&settings.tmp_dir)); + let tmp_dir = crash_if_err!( + 1, + tempfile::Builder::new() + .prefix("uutils_sort") + .tempdir_in(&settings.tmp_dir) + ); let (sorted_sender, sorted_receiver) = std::sync::mpsc::sync_channel(1); let (recycled_sender, recycled_receiver) = std::sync::mpsc::sync_channel(1); thread::spawn({ diff --git a/src/uu/stdbuf/src/stdbuf.rs b/src/uu/stdbuf/src/stdbuf.rs index 485b3c70e..134247060 100644 --- a/src/uu/stdbuf/src/stdbuf.rs +++ b/src/uu/stdbuf/src/stdbuf.rs @@ -25,8 +25,7 @@ static VERSION: &str = env!("CARGO_PKG_VERSION"); static ABOUT: &str = "Run COMMAND, with modified buffering operations for its standard streams.\n\n\ Mandatory arguments to long options are mandatory for short options too."; -static LONG_HELP: &str = - "If MODE is 'L' the corresponding stream will be line buffered.\n\ +static LONG_HELP: &str = "If MODE is 'L' the corresponding stream will be line buffered.\n\ This option is invalid with standard input.\n\n\ If MODE is '0' the corresponding stream will be unbuffered.\n\n\ Otherwise MODE is a number which may be followed by one of the following:\n\n\ From a9e0208ee21f35e124ad089e240b933a68b248fb Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Fri, 28 May 2021 17:49:28 +0200 Subject: [PATCH 11/39] maint: remove obsolete attributes --- src/uucore_procs/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/uucore_procs/src/lib.rs b/src/uucore_procs/src/lib.rs index 10368a5bd..e0d247c3f 100644 --- a/src/uucore_procs/src/lib.rs +++ b/src/uucore_procs/src/lib.rs @@ -1,6 +1,3 @@ -#![allow(dead_code)] // work-around for GH:rust-lang/rust#62127; maint: can be removed when MinSRV >= v1.38.0 -#![allow(unused_macros)] // work-around for GH:rust-lang/rust#62127; maint: can be removed when MinSRV >= v1.38.0 - // Copyright (C) ~ Roy Ivy III ; MIT license extern crate proc_macro; @@ -44,7 +41,6 @@ impl syn::parse::Parse for Tokens { } #[proc_macro] -#[cfg(not(test))] // work-around for GH:rust-lang/rust#62127; maint: can be removed when MinSRV >= v1.38.0 pub fn main(stream: proc_macro::TokenStream) -> proc_macro::TokenStream { let Tokens { expr } = syn::parse_macro_input!(stream as Tokens); proc_dbg!(&expr); From 6a9ffee54814b54b5ff367e53f4569b0b70fdded Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Fri, 28 May 2021 18:28:00 +0300 Subject: [PATCH 12/39] Moved factor to use clap Issue: https://github.com/uutils/coreutils/issues/2121 --- Cargo.lock | 1 + src/uu/factor/Cargo.toml | 1 + src/uu/factor/src/cli.rs | 36 ++++++++++++++++++++---------------- tests/by-util/test_factor.rs | 12 ++++++++++++ 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 461ce5487..ef22c052d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2054,6 +2054,7 @@ dependencies = [ name = "uu_factor" version = "0.0.6" dependencies = [ + "clap", "coz", "num-traits", "paste", diff --git a/src/uu/factor/Cargo.toml b/src/uu/factor/Cargo.toml index eb34519f1..eb977760f 100644 --- a/src/uu/factor/Cargo.toml +++ b/src/uu/factor/Cargo.toml @@ -21,6 +21,7 @@ rand = { version = "0.7", features = ["small_rng"] } smallvec = { version = "0.6.14, < 1.0" } uucore = { version = ">=0.0.8", package = "uucore", path = "../../uucore" } uucore_procs = { version = ">=0.0.5", package = "uucore_procs", path = "../../uucore_procs" } +clap = "2.33" [dev-dependencies] paste = "0.1.18" diff --git a/src/uu/factor/src/cli.rs b/src/uu/factor/src/cli.rs index ee4c8a4c4..69a368479 100644 --- a/src/uu/factor/src/cli.rs +++ b/src/uu/factor/src/cli.rs @@ -13,18 +13,21 @@ use std::error::Error; use std::io::{self, stdin, stdout, BufRead, Write}; mod factor; +use clap::{App, Arg}; pub use factor::*; -use uucore::InvalidEncodingHandling; mod miller_rabin; pub mod numeric; mod rho; pub mod table; -static SYNTAX: &str = "[OPTION] [NUMBER]..."; -static SUMMARY: &str = "Print the prime factors of the given number(s). - If none are specified, read from standard input."; -static LONG_HELP: &str = ""; +static VERSION: &str = env!("CARGO_PKG_VERSION"); +static SUMMARY: &str = "Print the prime factors of the given NUMBER(s). +If none are specified, read from standard input."; + +mod options { + pub static NUMBER: &str = "NUMBER"; +} fn print_factors_str(num_str: &str, w: &mut impl io::Write) -> Result<(), Box> { num_str @@ -34,14 +37,21 @@ fn print_factors_str(num_str: &str, w: &mut impl io::Write) -> Result<(), Box i32 { - let matches = app!(SYNTAX, SUMMARY, LONG_HELP).parse( - args.collect_str(InvalidEncodingHandling::Ignore) - .accept_any(), - ); + let matches = App::new(executable!()) + .version(VERSION) + .about(SUMMARY) + .arg(Arg::with_name(options::NUMBER).multiple(true)) + .get_matches_from(args); let stdout = stdout(); let mut w = io::BufWriter::new(stdout.lock()); - if matches.free.is_empty() { + if let Some(values) = matches.values_of(options::NUMBER) { + for number in values { + if let Err(e) = print_factors_str(number, &mut w) { + show_warning!("{}: {}", number, e); + } + } + } else { let stdin = stdin(); for line in stdin.lock().lines() { @@ -51,12 +61,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 { } } } - } else { - for number in &matches.free { - if let Err(e) = print_factors_str(number, &mut w) { - show_warning!("{}: {}", number, e); - } - } } if let Err(e) = w.flush() { diff --git a/tests/by-util/test_factor.rs b/tests/by-util/test_factor.rs index af2ff4ddb..7b856d1b8 100644 --- a/tests/by-util/test_factor.rs +++ b/tests/by-util/test_factor.rs @@ -39,6 +39,18 @@ fn test_first_100000_integers() { assert_eq!(hash_check, "4ed2d8403934fa1c76fe4b84c5d4b8850299c359"); } +#[test] +fn test_cli_args() { + // Make sure that factor works with CLI arguments as well. + new_ucmd!().args(&["3"]).succeeds().stdout_contains("3: 3"); + + new_ucmd!() + .args(&["3", "6"]) + .succeeds() + .stdout_contains("3: 3") + .stdout_contains("6: 2 3"); +} + #[test] fn test_random() { use conv::prelude::*; From b5cbd506bcd8516ea790ffd9e01252f8c02b6f15 Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Fri, 28 May 2021 18:58:06 +0200 Subject: [PATCH 13/39] maint: remove trailing commas from matches Trailing commas are only supported starting from 1.48. --- src/uu/sort/src/numeric_str_cmp.rs | 2 +- src/uu/sort/src/sort.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uu/sort/src/numeric_str_cmp.rs b/src/uu/sort/src/numeric_str_cmp.rs index 76dc81aeb..2935f55e8 100644 --- a/src/uu/sort/src/numeric_str_cmp.rs +++ b/src/uu/sort/src/numeric_str_cmp.rs @@ -70,7 +70,7 @@ impl NumInfo { if matches!( parse_settings.thousands_separator, - Some(c) if c == char, + Some(c) if c == char ) { continue; } diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index cc391af00..001e59c18 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -585,7 +585,7 @@ impl FieldSelector { && to.is_none() && !matches!( settings.mode, - SortMode::Numeric | SortMode::GeneralNumeric | SortMode::HumanNumeric, + SortMode::Numeric | SortMode::GeneralNumeric | SortMode::HumanNumeric ), needs_tokens: from.field != 1 || from.char == 0 || to.is_some(), from, From e9656a6c32fb84a4f864dc88b34c7a537462769b Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Fri, 28 May 2021 22:38:29 +0200 Subject: [PATCH 14/39] sort: make GNU test sort-debug-keys pass (#2269) * sort: disable support for thousand separators In order to be compatible with GNU, we have to disable thousands separators. GNU does not enable them for the C locale, either. Once we add support for locales we can add this feature back. * sort: delete unused fixtures * sort: compare -0 and 0 equal I must have misunderstood this when implementing, but GNU considers -0, 0, and invalid numbers to be equal. * sort: strip blanks before applying the char index * sort: don't crash when key start is after key end * sort: add "no match" for months at the first non-whitespace char We should put the "^ no match for key" indicator at the first non-whitespace character of a field. * sort: improve support for e notation * sort: use maches! macros --- src/uu/sort/src/numeric_str_cmp.rs | 10 +- src/uu/sort/src/sort.rs | 92 ++++++++++++------- tests/by-util/test_sort.rs | 12 +++ .../fixtures/sort/exponents_general.expected | 9 ++ .../sort/exponents_general.expected.debug | 27 ++++++ tests/fixtures/sort/exponents_general.txt | 9 ++ tests/fixtures/sort/keys_blanks.expected | 3 + .../fixtures/sort/keys_blanks.expected.debug | 9 ++ tests/fixtures/sort/keys_blanks.txt | 3 + .../fixtures/sort/keys_negative_size.expected | 1 + .../sort/keys_negative_size.expected.debug | 3 + tests/fixtures/sort/keys_negative_size.txt | 1 + .../mixed_floats_ints_chars_numeric.expected | 4 +- ...d_floats_ints_chars_numeric.expected.debug | 12 +-- ...floats_ints_chars_numeric_reverse.expected | 30 ------ ...ints_chars_numeric_reverse_stable.expected | 30 ------ ...oats_ints_chars_numeric_reverse_stable.txt | 30 ------ ..._floats_ints_chars_numeric_stable.expected | 7 +- ...s_ints_chars_numeric_stable.expected.debug | 14 ++- ...mixed_floats_ints_chars_numeric_stable.txt | 3 + ..._floats_ints_chars_numeric_unique.expected | 3 +- ...s_ints_chars_numeric_unique.expected.debug | 6 +- ...ints_chars_numeric_unique_reverse.expected | 3 +- ...hars_numeric_unique_reverse.expected.debug | 6 +- ...ars_numeric_unique_reverse_stable.expected | 20 ---- ..._ints_chars_numeric_unique_stable.expected | 20 ---- ...loats_ints_chars_numeric_unique_stable.txt | 30 ------ tests/fixtures/sort/month_default.expected | 1 + .../sort/month_default.expected.debug | 3 + tests/fixtures/sort/month_default.txt | 1 + tests/fixtures/sort/month_stable.expected | 1 + .../fixtures/sort/month_stable.expected.debug | 2 + tests/fixtures/sort/month_stable.txt | 1 + .../sort/multiple_decimals_numeric.expected | 4 +- .../multiple_decimals_numeric.expected.debug | 12 +-- 35 files changed, 191 insertions(+), 231 deletions(-) create mode 100644 tests/fixtures/sort/keys_blanks.expected create mode 100644 tests/fixtures/sort/keys_blanks.expected.debug create mode 100644 tests/fixtures/sort/keys_blanks.txt create mode 100644 tests/fixtures/sort/keys_negative_size.expected create mode 100644 tests/fixtures/sort/keys_negative_size.expected.debug create mode 100644 tests/fixtures/sort/keys_negative_size.txt delete mode 100644 tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse.expected delete mode 100644 tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse_stable.expected delete mode 100644 tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse_stable.txt delete mode 100644 tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse_stable.expected delete mode 100644 tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_stable.expected delete mode 100644 tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_stable.txt diff --git a/src/uu/sort/src/numeric_str_cmp.rs b/src/uu/sort/src/numeric_str_cmp.rs index 2935f55e8..03806b0c8 100644 --- a/src/uu/sort/src/numeric_str_cmp.rs +++ b/src/uu/sort/src/numeric_str_cmp.rs @@ -174,7 +174,11 @@ impl NumInfo { pub fn numeric_str_cmp((a, a_info): (&str, &NumInfo), (b, b_info): (&str, &NumInfo)) -> Ordering { // check for a difference in the sign if a_info.sign != b_info.sign { - return a_info.sign.cmp(&b_info.sign); + return if a.is_empty() && b.is_empty() { + Ordering::Equal + } else { + a_info.sign.cmp(&b_info.sign) + }; } // check for a difference in the exponent @@ -419,8 +423,8 @@ mod tests { #[test] fn minus_zero() { // This matches GNU sort behavior. - test_helper("-0", "0", Ordering::Less); - test_helper("-0x", "0", Ordering::Less); + test_helper("-0", "0", Ordering::Equal); + test_helper("-0x", "0", Ordering::Equal); } #[test] fn double_minus() { diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 001e59c18..77be78390 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -99,10 +99,9 @@ static OPT_TMP_DIR: &str = "temporary-directory"; static ARG_FILES: &str = "files"; static DECIMAL_PT: char = '.'; -static THOUSANDS_SEP: char = ','; -static NEGATIVE: char = '-'; -static POSITIVE: char = '+'; +const NEGATIVE: char = '-'; +const POSITIVE: char = '+'; // Choosing a higher buffer size does not result in performance improvements // (at least not on my machine). TODO: In the future, we should also take the amount of @@ -330,8 +329,7 @@ impl<'a> Line<'a> { &self.line[selection.clone()], NumInfoParseSettings { accept_si_units: selector.settings.mode == SortMode::HumanNumeric, - thousands_separator: Some(THOUSANDS_SEP), - decimal_pt: Some(DECIMAL_PT), + ..Default::default() }, ); let initial_selection = selection.clone(); @@ -367,16 +365,24 @@ impl<'a> Line<'a> { SortMode::Month => { let initial_selection = &self.line[selection.clone()]; + let mut month_chars = initial_selection + .char_indices() + .skip_while(|(_, c)| c.is_whitespace()); + let month = if month_parse(initial_selection) == Month::Unknown { // We failed to parse a month, which is equivalent to matching nothing. - 0..0 + // Add the "no match for key" marker to the first non-whitespace character. + let first_non_whitespace = month_chars.next(); + first_non_whitespace.map_or( + initial_selection.len()..initial_selection.len(), + |(idx, _)| idx..idx, + ) } else { - // We parsed a month. Match the three first non-whitespace characters, which must be the month we parsed. - let mut chars = initial_selection - .char_indices() - .skip_while(|(_, c)| c.is_whitespace()); - chars.next().unwrap().0 - ..chars.nth(2).map_or(initial_selection.len(), |(idx, _)| idx) + // We parsed a month. Match the first three non-whitespace characters, which must be the month we parsed. + month_chars.next().unwrap().0 + ..month_chars + .nth(2) + .map_or(initial_selection.len(), |(idx, _)| idx) }; // Shorten selection to month. @@ -606,8 +612,7 @@ impl FieldSelector { range, NumInfoParseSettings { accept_si_units: self.settings.mode == SortMode::HumanNumeric, - thousands_separator: Some(THOUSANDS_SEP), - decimal_pt: Some(DECIMAL_PT), + ..Default::default() }, ); // Shorten the range to what we need to pass to numeric_str_cmp later. @@ -666,22 +671,21 @@ impl FieldSelector { } else { tokens.unwrap()[position.field - 1].start }; + // strip blanks if needed + if position.ignore_blanks { + idx += line[idx..] + .char_indices() + .find(|(_, c)| !c.is_whitespace()) + .map_or(line[idx..].len(), |(idx, _)| idx); + } + // apply the character index idx += line[idx..] .char_indices() .nth(position.char - 1) - .map_or(line.len(), |(idx, _)| idx); + .map_or(line[idx..].len(), |(idx, _)| idx); if idx >= line.len() { Resolution::TooHigh } else { - if position.ignore_blanks { - if let Some((not_whitespace, _)) = - line[idx..].char_indices().find(|(_, c)| !c.is_whitespace()) - { - idx += not_whitespace; - } else { - return Resolution::TooHigh; - } - } Resolution::StartOfChar(idx) } } @@ -691,8 +695,9 @@ impl FieldSelector { Resolution::StartOfChar(from) => { let to = self.to.as_ref().map(|to| resolve_index(line, tokens, &to)); - match to { + let mut range = match to { Some(Resolution::StartOfChar(mut to)) => { + // We need to include the character at `to`. to += line[to..].chars().next().map_or(1, |c| c.len_utf8()); from..to } @@ -703,7 +708,11 @@ impl FieldSelector { // If `to` is before the start of the line, report no match. // This can happen if the line starts with a separator. Some(Resolution::TooLow) => 0..0, + }; + if range.start > range.end { + range.end = range.start; } + range } Resolution::TooLow | Resolution::EndOfChar(_) => { unreachable!("This should only happen if the field start index is 0, but that should already have caused an error.") @@ -1202,6 +1211,8 @@ fn compare_by<'a>(a: &Line<'a>, b: &Line<'a>, global_settings: &GlobalSettings) fn get_leading_gen(input: &str) -> Range { let trimmed = input.trim_start(); let leading_whitespace_len = input.len() - trimmed.len(); + + // check for inf, -inf and nan for allowed_prefix in &["inf", "-inf", "nan"] { if trimmed.is_char_boundary(allowed_prefix.len()) && trimmed[..allowed_prefix.len()].eq_ignore_ascii_case(allowed_prefix) @@ -1210,11 +1221,11 @@ fn get_leading_gen(input: &str) -> Range { } } // Make this iter peekable to see if next char is numeric - let mut char_indices = trimmed.char_indices().peekable(); + let mut char_indices = itertools::peek_nth(trimmed.char_indices()); let first = char_indices.peek(); - if first.map_or(false, |&(_, c)| c == NEGATIVE || c == POSITIVE) { + if matches!(first, Some((_, NEGATIVE)) | Some((_, POSITIVE))) { char_indices.next(); } @@ -1224,16 +1235,29 @@ fn get_leading_gen(input: &str) -> Range { if c.is_ascii_digit() { continue; } - if c == DECIMAL_PT && !had_decimal_pt { + if c == DECIMAL_PT && !had_decimal_pt && !had_e_notation { had_decimal_pt = true; continue; } - let next_char_numeric = char_indices - .peek() - .map_or(false, |(_, c)| c.is_ascii_digit()); - if (c == 'e' || c == 'E') && !had_e_notation && next_char_numeric { - had_e_notation = true; - continue; + if (c == 'e' || c == 'E') && !had_e_notation { + // we can only consume the 'e' if what follow is either a digit, or a sign followed by a digit. + if let Some(&(_, next_char)) = char_indices.peek() { + if (next_char == '+' || next_char == '-') + && matches!( + char_indices.peek_nth(2), + Some((_, c)) if c.is_ascii_digit() + ) + { + // Consume the sign. The following digits will be consumed by the main loop. + char_indices.next(); + had_e_notation = true; + continue; + } + if next_char.is_ascii_digit() { + had_e_notation = true; + continue; + } + } } return leading_whitespace_len..(leading_whitespace_len + idx); } diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index 133dc0028..624c002d0 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -526,6 +526,11 @@ fn test_keys_with_options_blanks_start() { } } +#[test] +fn test_keys_blanks_with_char_idx() { + test_helper("keys_blanks", &["-k 1.2b"]) +} + #[test] fn test_keys_with_options_blanks_end() { let input = "a b @@ -574,6 +579,13 @@ aaaa .stdout_only(input); } +#[test] +fn test_keys_negative_size_match() { + // If the end of a field is before its start, we should not crash. + // Debug output should report "no match for key" at the start position (i.e. the later position). + test_helper("keys_negative_size", &["-k 3,1"]); +} + #[test] fn test_zero_terminated() { test_helper("zero-terminated", &["-z"]); diff --git a/tests/fixtures/sort/exponents_general.expected b/tests/fixtures/sort/exponents_general.expected index 524b6e67f..308a82e1e 100644 --- a/tests/fixtures/sort/exponents_general.expected +++ b/tests/fixtures/sort/exponents_general.expected @@ -6,8 +6,15 @@ + -12e-5555.5 +0b10 // binary not supported +0x10 // hexadecimal not supported, but it should be +55e-20 +55e-20.10 5.5.5.5 10E +64e+ +99e- 1000EDKLD 10000K78 +100000 @@ -15,5 +22,7 @@ 100E6 100E6 10e10e10e10 +13e+10 +45e+10.5 50e10 50e10 diff --git a/tests/fixtures/sort/exponents_general.expected.debug b/tests/fixtures/sort/exponents_general.expected.debug index 4dea45c39..a7238d10e 100644 --- a/tests/fixtures/sort/exponents_general.expected.debug +++ b/tests/fixtures/sort/exponents_general.expected.debug @@ -22,12 +22,33 @@ ^ no match for key ^ no match for key + > -12e-5555.5 + _________ +______________ +0b10 // binary not supported +_ +____________________________ +0x10 // hexadecimal not supported, but it should be +_ +___________________________________________________ +55e-20 +______ +______ +55e-20.10 +______ +_________ 5.5.5.5 ___ _______ 10E __ ___ +64e+ +__ +____ +99e- +__ +____ 1000EDKLD ____ _________ @@ -49,6 +70,12 @@ _____ 10e10e10e10 _____ ___________ +13e+10 +______ +______ +45e+10.5 +______ +________ 50e10 _____ _____ diff --git a/tests/fixtures/sort/exponents_general.txt b/tests/fixtures/sort/exponents_general.txt index de2a6c31b..4a9bbba2e 100644 --- a/tests/fixtures/sort/exponents_general.txt +++ b/tests/fixtures/sort/exponents_general.txt @@ -4,16 +4,25 @@ +100000 10000K78 +0x10 // hexadecimal not supported, but it should be 10E +0b10 // binary not supported +64e+ +99e- +45e+10.5 1000EDKLD +13e+10 100E6 50e10 + -12e-5555.5 +100000 10e10e10e10 5.5.5.5 +55e-20 +55e-20.10 diff --git a/tests/fixtures/sort/keys_blanks.expected b/tests/fixtures/sort/keys_blanks.expected new file mode 100644 index 000000000..1789659c4 --- /dev/null +++ b/tests/fixtures/sort/keys_blanks.expected @@ -0,0 +1,3 @@ + cab + abc + bca diff --git a/tests/fixtures/sort/keys_blanks.expected.debug b/tests/fixtures/sort/keys_blanks.expected.debug new file mode 100644 index 000000000..bb09ea8a2 --- /dev/null +++ b/tests/fixtures/sort/keys_blanks.expected.debug @@ -0,0 +1,9 @@ +>cab + __ +____ +>abc + __ +____ +>bca + __ +____ diff --git a/tests/fixtures/sort/keys_blanks.txt b/tests/fixtures/sort/keys_blanks.txt new file mode 100644 index 000000000..7c4f313a3 --- /dev/null +++ b/tests/fixtures/sort/keys_blanks.txt @@ -0,0 +1,3 @@ + abc + cab + bca diff --git a/tests/fixtures/sort/keys_negative_size.expected b/tests/fixtures/sort/keys_negative_size.expected new file mode 100644 index 000000000..3774da60e --- /dev/null +++ b/tests/fixtures/sort/keys_negative_size.expected @@ -0,0 +1 @@ +a b c diff --git a/tests/fixtures/sort/keys_negative_size.expected.debug b/tests/fixtures/sort/keys_negative_size.expected.debug new file mode 100644 index 000000000..e392ec7f3 --- /dev/null +++ b/tests/fixtures/sort/keys_negative_size.expected.debug @@ -0,0 +1,3 @@ +a b c + ^ no match for key +_____ diff --git a/tests/fixtures/sort/keys_negative_size.txt b/tests/fixtures/sort/keys_negative_size.txt new file mode 100644 index 000000000..3774da60e --- /dev/null +++ b/tests/fixtures/sort/keys_negative_size.txt @@ -0,0 +1 @@ +a b c diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected index a781a36bb..59541af32 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected @@ -21,10 +21,10 @@ CARAvan 8.013 45 46.89 - 4567. - 37800 576,446.88800000 576,446.890 + 4567. + 37800 4798908.340000000000 4798908.45 4798908.8909800 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected.debug b/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected.debug index dbe295a1c..b7b76e589 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected.debug +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected.debug @@ -67,18 +67,18 @@ __ 46.89 _____ _____ +576,446.88800000 +___ +________________ +576,446.890 +___ +___________ 4567. _____ ____________________ >>>>37800 _____ _________ -576,446.88800000 -________________ -________________ -576,446.890 -___________ -___________ 4798908.340000000000 ____________________ ____________________ diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse.expected deleted file mode 100644 index 6b024210b..000000000 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse.expected +++ /dev/null @@ -1,30 +0,0 @@ -4798908.8909800 -4798908.45 -4798908.340000000000 -576,446.890 -576,446.88800000 - 37800 - 4567. -46.89 -45 -8.013 -1.58590 -1.444 -1.040000000 -1 -00000001 -CARAvan -000 - - - - - - - - --.05 --1 --8.90880 --896689 --2028789030 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse_stable.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse_stable.expected deleted file mode 100644 index cb1028f0e..000000000 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse_stable.expected +++ /dev/null @@ -1,30 +0,0 @@ -4798908.8909800 -4798908.45 -4798908.340000000000 -576,446.890 -576,446.88800000 - 37800 - 4567. -46.89 -45 -8.013 -1.58590 -1.444 -1.040000000 -1 -00000001 - - - - - -CARAvan - - - -000 --.05 --1 --8.90880 --896689 --2028789030 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse_stable.txt b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse_stable.txt deleted file mode 100644 index a5813ea3a..000000000 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_reverse_stable.txt +++ /dev/null @@ -1,30 +0,0 @@ -576,446.890 -576,446.88800000 - - - 4567. -45 -46.89 --1 -1 -00000001 -4798908.340000000000 -4798908.45 -4798908.8909800 - - - 37800 - --2028789030 --896689 -CARAvan - --8.90880 --.05 -1.444 -1.58590 -1.040000000 - -8.013 - -000 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected index 63a3e646d..0ccdd84c0 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected @@ -8,11 +8,14 @@ +-0 CARAvan +-0 000 +-0 1 00000001 1.040000000 @@ -21,10 +24,10 @@ CARAvan 8.013 45 46.89 +576,446.890 +576,446.88800000 4567. 37800 -576,446.88800000 -576,446.890 4798908.340000000000 4798908.45 4798908.8909800 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected.debug b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected.debug index b2782d93d..66a98b208 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected.debug +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected.debug @@ -18,8 +18,12 @@ ____ ^ no match for key ^ no match for key +-0 +__ CARAvan ^ no match for key +-0 +__ ^ no match for key @@ -28,6 +32,8 @@ CARAvan ^ no match for key 000 ___ +-0 +__ 1 _ 00000001 @@ -44,14 +50,14 @@ _____ __ 46.89 _____ +576,446.890 +___ +576,446.88800000 +___ 4567. _____ >>>>37800 _____ -576,446.88800000 -________________ -576,446.890 -___________ 4798908.340000000000 ____________________ 4798908.45 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.txt b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.txt index a5813ea3a..44667ef03 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.txt +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.txt @@ -17,7 +17,9 @@ -2028789030 -896689 +-0 CARAvan +-0 -8.90880 -.05 @@ -28,3 +30,4 @@ CARAvan 8.013 000 +-0 \ No newline at end of file diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected index cb27c6664..cd4256c5f 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected @@ -11,10 +11,9 @@ 8.013 45 46.89 +576,446.890 4567. 37800 -576,446.88800000 -576,446.890 4798908.340000000000 4798908.45 4798908.8909800 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected.debug b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected.debug index 782a77724..663a4b3a9 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected.debug +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected.debug @@ -24,14 +24,12 @@ _____ __ 46.89 _____ +576,446.890 +___ 4567. _____ >>>>37800 _____ -576,446.88800000 -________________ -576,446.890 -___________ 4798908.340000000000 ____________________ 4798908.45 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected index bbce16934..97e261f14 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected @@ -1,10 +1,9 @@ 4798908.8909800 4798908.45 4798908.340000000000 -576,446.890 -576,446.88800000 37800 4567. +576,446.890 46.89 45 8.013 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected.debug b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected.debug index e0389c1d5..01f7abf5b 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected.debug +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected.debug @@ -4,14 +4,12 @@ _______________ __________ 4798908.340000000000 ____________________ -576,446.890 -___________ -576,446.88800000 -________________ >>>>37800 _____ 4567. _____ +576,446.890 +___ 46.89 _____ 45 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse_stable.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse_stable.expected deleted file mode 100644 index bbce16934..000000000 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse_stable.expected +++ /dev/null @@ -1,20 +0,0 @@ -4798908.8909800 -4798908.45 -4798908.340000000000 -576,446.890 -576,446.88800000 - 37800 - 4567. -46.89 -45 -8.013 -1.58590 -1.444 -1.040000000 -1 - --.05 --1 --8.90880 --896689 --2028789030 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_stable.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_stable.expected deleted file mode 100644 index bbce16934..000000000 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_stable.expected +++ /dev/null @@ -1,20 +0,0 @@ -4798908.8909800 -4798908.45 -4798908.340000000000 -576,446.890 -576,446.88800000 - 37800 - 4567. -46.89 -45 -8.013 -1.58590 -1.444 -1.040000000 -1 - --.05 --1 --8.90880 --896689 --2028789030 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_stable.txt b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_stable.txt deleted file mode 100644 index a5813ea3a..000000000 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_stable.txt +++ /dev/null @@ -1,30 +0,0 @@ -576,446.890 -576,446.88800000 - - - 4567. -45 -46.89 --1 -1 -00000001 -4798908.340000000000 -4798908.45 -4798908.8909800 - - - 37800 - --2028789030 --896689 -CARAvan - --8.90880 --.05 -1.444 -1.58590 -1.040000000 - -8.013 - -000 diff --git a/tests/fixtures/sort/month_default.expected b/tests/fixtures/sort/month_default.expected index dc51f5d5e..99baa235a 100644 --- a/tests/fixtures/sort/month_default.expected +++ b/tests/fixtures/sort/month_default.expected @@ -1,3 +1,4 @@ + asdf N/A Ut enim ad minim veniam, quis Jan Lorem ipsum dolor sit amet mar laboris nisi ut aliquip ex ea diff --git a/tests/fixtures/sort/month_default.expected.debug b/tests/fixtures/sort/month_default.expected.debug index 2c55a0e2a..f28ba1c48 100644 --- a/tests/fixtures/sort/month_default.expected.debug +++ b/tests/fixtures/sort/month_default.expected.debug @@ -1,3 +1,6 @@ + asdf + ^ no match for key +_____ N/A Ut enim ad minim veniam, quis ^ no match for key _________________________________ diff --git a/tests/fixtures/sort/month_default.txt b/tests/fixtures/sort/month_default.txt index 6d64bf4f8..c96bad300 100644 --- a/tests/fixtures/sort/month_default.txt +++ b/tests/fixtures/sort/month_default.txt @@ -8,3 +8,4 @@ mar laboris nisi ut aliquip ex ea Jul 2 these three lines Jul 1 should remain 2,1,3 Jul 3 if --stable is provided + asdf diff --git a/tests/fixtures/sort/month_stable.expected b/tests/fixtures/sort/month_stable.expected index 868728a18..cb3a8da8f 100644 --- a/tests/fixtures/sort/month_stable.expected +++ b/tests/fixtures/sort/month_stable.expected @@ -1,4 +1,5 @@ N/A Ut enim ad minim veniam, quis + asdf Jan Lorem ipsum dolor sit amet mar laboris nisi ut aliquip ex ea May sed do eiusmod tempor incididunt diff --git a/tests/fixtures/sort/month_stable.expected.debug b/tests/fixtures/sort/month_stable.expected.debug index 4163ba39a..740f9187c 100644 --- a/tests/fixtures/sort/month_stable.expected.debug +++ b/tests/fixtures/sort/month_stable.expected.debug @@ -1,5 +1,7 @@ N/A Ut enim ad minim veniam, quis ^ no match for key + asdf + ^ no match for key Jan Lorem ipsum dolor sit amet ___ mar laboris nisi ut aliquip ex ea diff --git a/tests/fixtures/sort/month_stable.txt b/tests/fixtures/sort/month_stable.txt index 6d64bf4f8..c96bad300 100644 --- a/tests/fixtures/sort/month_stable.txt +++ b/tests/fixtures/sort/month_stable.txt @@ -8,3 +8,4 @@ mar laboris nisi ut aliquip ex ea Jul 2 these three lines Jul 1 should remain 2,1,3 Jul 3 if --stable is provided + asdf diff --git a/tests/fixtures/sort/multiple_decimals_numeric.expected b/tests/fixtures/sort/multiple_decimals_numeric.expected index 3ef4d22e8..8f42e7ce5 100644 --- a/tests/fixtures/sort/multiple_decimals_numeric.expected +++ b/tests/fixtures/sort/multiple_decimals_numeric.expected @@ -21,6 +21,8 @@ CARAvan 8.013 45 46.89 +576,446.88800000 +576,446.890 4567..457 4567. 4567.1 @@ -28,8 +30,6 @@ CARAvan 37800 45670.89079.098 45670.89079.1 -576,446.88800000 -576,446.890 4798908.340000000000 4798908.45 4798908.8909800 diff --git a/tests/fixtures/sort/multiple_decimals_numeric.expected.debug b/tests/fixtures/sort/multiple_decimals_numeric.expected.debug index f40ade9aa..948c4869c 100644 --- a/tests/fixtures/sort/multiple_decimals_numeric.expected.debug +++ b/tests/fixtures/sort/multiple_decimals_numeric.expected.debug @@ -67,6 +67,12 @@ __ 46.89 _____ _____ +576,446.88800000 +___ +________________ +576,446.890 +___ +___________ >>>>>>>>>>4567..457 _____ ___________________ @@ -88,12 +94,6 @@ _____________________ >>>>>>45670.89079.1 ___________ ___________________ -576,446.88800000 -________________ -________________ -576,446.890 -___________ -___________ 4798908.340000000000 ____________________ ____________________ From bb268d1500eabc2bf8efa193de4fc4923a06b66a Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Fri, 28 May 2021 22:39:33 +0200 Subject: [PATCH 15/39] sort: crash when failing to open an input file (#2265) * sort: crash when failing to open an input file Instead of ignoring files we fail to open, crash. The error message does not exactly match gnu, but that would require more effort. * use split_whitespace instead of a manual implementation * fix expected error on windows * sort: update expected error message --- src/uu/sort/src/check.rs | 2 +- src/uu/sort/src/merge.rs | 2 +- src/uu/sort/src/sort.rs | 13 ++++++------- tests/by-util/test_sort.rs | 18 ++++++++++++++++-- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/uu/sort/src/check.rs b/src/uu/sort/src/check.rs index 01b5a25b5..d3b9d6669 100644 --- a/src/uu/sort/src/check.rs +++ b/src/uu/sort/src/check.rs @@ -26,7 +26,7 @@ use std::{ /// /// The code we should exit with. pub fn check(path: &str, settings: &GlobalSettings) -> i32 { - let file = open(path).expect("failed to open input file"); + let file = open(path); let (recycled_sender, recycled_receiver) = sync_channel(2); let (loaded_sender, loaded_receiver) = sync_channel(2); thread::spawn({ diff --git a/src/uu/sort/src/merge.rs b/src/uu/sort/src/merge.rs index 48d48ad40..696353829 100644 --- a/src/uu/sort/src/merge.rs +++ b/src/uu/sort/src/merge.rs @@ -29,7 +29,7 @@ pub fn merge<'a>(files: &[impl AsRef], settings: &'a GlobalSettings) -> F let (request_sender, request_receiver) = channel(); let mut reader_files = Vec::with_capacity(files.len()); let mut loaded_receivers = Vec::with_capacity(files.len()); - for (file_number, file) in files.iter().filter_map(open).enumerate() { + for (file_number, file) in files.iter().map(open).enumerate() { let (sender, receiver) = sync_channel(2); loaded_receivers.push(receiver); reader_files.push(ReaderFile { diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 77be78390..0efce00e6 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -955,7 +955,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let mut files = Vec::new(); for path in &files0_from { - let reader = open(path.as_str()).expect("Could not read from file specified."); + let reader = open(path.as_str()); let buf_reader = BufReader::new(reader); for line in buf_reader.split(b'\0').flatten() { files.push( @@ -1116,7 +1116,7 @@ fn exec(files: &[String], settings: &GlobalSettings) -> i32 { } return check::check(files.first().unwrap(), settings); } else { - let mut lines = files.iter().filter_map(open); + let mut lines = files.iter().map(open); ext_sort(&mut lines, &settings); } @@ -1413,18 +1413,17 @@ fn print_sorted<'a, T: Iterator>>(iter: T, settings: &Global } // from cat.rs -fn open(path: impl AsRef) -> Option> { +fn open(path: impl AsRef) -> Box { let path = path.as_ref(); if path == "-" { let stdin = stdin(); - return Some(Box::new(stdin) as Box); + return Box::new(stdin) as Box; } match File::open(Path::new(path)) { - Ok(f) => Some(Box::new(f) as Box), + Ok(f) => Box::new(f) as Box, Err(e) => { - show_error!("{0:?}: {1}", path, e.to_string()); - None + crash!(2, "cannot read: {0:?}: {1}", path, e); } } } diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index 624c002d0..3c0af259f 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -4,14 +4,14 @@ fn test_helper(file_name: &str, possible_args: &[&str]) { for args in possible_args { new_ucmd!() .arg(format!("{}.txt", file_name)) - .args(&args.split(' ').collect::>()) + .args(&args.split_whitespace().collect::>()) .succeeds() .stdout_is_fixture(format!("{}.expected", file_name)); new_ucmd!() .arg(format!("{}.txt", file_name)) .arg("--debug") - .args(&args.split(' ').collect::>()) + .args(&args.split_whitespace().collect::>()) .succeeds() .stdout_is_fixture(format!("{}.expected.debug", file_name)); } @@ -723,3 +723,17 @@ fn test_trailing_separator() { .succeeds() .stdout_is("aax\naaa\n"); } + +#[test] +fn test_nonexistent_file() { + new_ucmd!() + .arg("nonexistent.txt") + .fails() + .status_code(2) + .stderr_only( + #[cfg(not(windows))] + "sort: cannot read: \"nonexistent.txt\": No such file or directory (os error 2)", + #[cfg(windows)] + "sort: cannot read: \"nonexistent.txt\": The system cannot find the file specified. (os error 2)", + ); +} From a2947f689780d526c760bd2b8ea7951c5b125876 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sat, 29 May 2021 00:46:25 +0200 Subject: [PATCH 16/39] fix clippy warning --- src/uu/basename/src/basename.rs | 2 +- src/uu/cp/src/cp.rs | 6 +++--- src/uu/csplit/src/csplit.rs | 9 +++++---- src/uu/ls/src/ls.rs | 3 +-- src/uu/od/src/parse_inputs.rs | 6 +++--- src/uu/printenv/src/printenv.rs | 9 +++++---- src/uu/ptx/src/ptx.rs | 11 +++++++---- src/uu/sort/src/sort.rs | 6 +++--- src/uucore/src/lib/lib.rs | 13 +++++++------ src/uucore/src/lib/mods/backup_control.rs | 2 +- 10 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/uu/basename/src/basename.rs b/src/uu/basename/src/basename.rs index c20561b30..e6476e436 100644 --- a/src/uu/basename/src/basename.rs +++ b/src/uu/basename/src/basename.rs @@ -136,7 +136,7 @@ fn basename(fullname: &str, suffix: &str) -> String { } } -#[allow(clippy::manual_strip)] // can be replaced with strip_suffix once the minimum rust version is 1.45 +// can be replaced with strip_suffix once the minimum rust version is 1.45 fn strip_suffix(name: &str, suffix: &str) -> String { if name == suffix { return name.to_owned(); diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index fab1dfec1..68ad3ed84 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -669,8 +669,8 @@ impl Options { } }, backup: backup_mode, - backup_suffix: backup_suffix, - overwrite: overwrite, + backup_suffix, + overwrite, no_target_dir, preserve_attributes, recursive, @@ -1089,7 +1089,7 @@ fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResu } #[cfg(not(windows))] -#[allow(clippy::unnecessary_wraps)] // needed for windows version +#[allow(clippy::unnecessary_unwrap)] // needed for windows version fn symlink_file(source: &Path, dest: &Path, context: &str) -> CopyResult<()> { match std::os::unix::fs::symlink(source, dest).context(context) { Ok(_) => Ok(()), diff --git a/src/uu/csplit/src/csplit.rs b/src/uu/csplit/src/csplit.rs index f67f4958f..43f95fff5 100644 --- a/src/uu/csplit/src/csplit.rs +++ b/src/uu/csplit/src/csplit.rs @@ -483,10 +483,11 @@ where /// Shrink the buffer so that its length is equal to the set size, returning an iterator for /// the elements that were too much. fn shrink_buffer_to_size(&mut self) -> impl Iterator + '_ { - let mut shrink_offset = 0; - if self.buffer.len() > self.size { - shrink_offset = self.buffer.len() - self.size; - } + let shrink_offset = if self.buffer.len() > self.size { + self.buffer.len() - self.size + } else { + 0 + }; self.buffer .drain(..shrink_offset) .map(|(_, line)| line.unwrap()) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index d467d431a..17e0a16a8 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -1614,7 +1614,7 @@ fn display_date(metadata: &Metadata, config: &Config) -> String { Some(time) => { //Date is recent if from past 6 months //According to GNU a Gregorian year has 365.2425 * 24 * 60 * 60 == 31556952 seconds on the average. - let recent = time + chrono::Duration::seconds(31556952 / 2) > chrono::Local::now(); + let recent = time + chrono::Duration::seconds(31_556_952 / 2) > chrono::Local::now(); match config.time_style { TimeStyle::FullIso => time.format("%Y-%m-%d %H:%M:%S.%f %z"), @@ -1696,7 +1696,6 @@ fn file_is_executable(md: &Metadata) -> bool { md.mode() & ((S_IXUSR | S_IXGRP | S_IXOTH) as u32) != 0 } -#[allow(clippy::clippy::collapsible_else_if)] fn classify_file(path: &PathData) -> Option { let file_type = path.file_type()?; diff --git a/src/uu/od/src/parse_inputs.rs b/src/uu/od/src/parse_inputs.rs index 533f4f106..288c0870f 100644 --- a/src/uu/od/src/parse_inputs.rs +++ b/src/uu/od/src/parse_inputs.rs @@ -76,7 +76,7 @@ pub fn parse_inputs(matches: &dyn CommandLineOpts) -> Result) -> Result CommandLineInputs::FileAndOffset(("-".to_string(), n, None)), _ => CommandLineInputs::FileNames( - input_strings.iter().map(|s| s.to_string()).collect(), + input_strings.iter().map(|&s| s.to_string()).collect(), ), }) } @@ -179,7 +179,7 @@ mod tests { impl<'a> MockOptions<'a> { fn new(inputs: Vec<&'a str>, option_names: Vec<&'a str>) -> MockOptions<'a> { MockOptions { - inputs: inputs.iter().map(|s| s.to_string()).collect::>(), + inputs: inputs.iter().map(|&s| s.to_string()).collect::>(), option_names, } } diff --git a/src/uu/printenv/src/printenv.rs b/src/uu/printenv/src/printenv.rs index 34571ddad..25cb58185 100644 --- a/src/uu/printenv/src/printenv.rs +++ b/src/uu/printenv/src/printenv.rs @@ -50,10 +50,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .map(|v| v.map(ToString::to_string).collect()) .unwrap_or_default(); - let mut separator = "\n"; - if matches.is_present(OPT_NULL) { - separator = "\x00"; - } + let separator = if matches.is_present(OPT_NULL) { + "\x00" + } else { + "\n" + }; if variables.is_empty() { for (env_var, value) in env::vars() { diff --git a/src/uu/ptx/src/ptx.rs b/src/uu/ptx/src/ptx.rs index d2aa619b4..a17f7c810 100644 --- a/src/uu/ptx/src/ptx.rs +++ b/src/uu/ptx/src/ptx.rs @@ -108,10 +108,13 @@ impl WordFilter { // Ignore empty string regex from cmd-line-args let arg_reg: Option = if matches.is_present(options::WORD_REGEXP) { match matches.value_of(options::WORD_REGEXP) { - Some(v) => match v.is_empty() { - true => None, - false => Some(v.to_string()), - }, + Some(v) => { + if v.is_empty() { + None + } else { + Some(v.to_string()) + } + } None => None, } } else { diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 0efce00e6..5fdaf32cf 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -296,10 +296,10 @@ impl<'a> Line<'a> { fn print(&self, writer: &mut impl Write, settings: &GlobalSettings) { if settings.zero_terminated && !settings.debug { crash_if_err!(1, writer.write_all(self.line.as_bytes())); - crash_if_err!(1, writer.write_all("\0".as_bytes())); + crash_if_err!(1, writer.write_all(b"\0")); } else if !settings.debug { crash_if_err!(1, writer.write_all(self.line.as_bytes())); - crash_if_err!(1, writer.write_all("\n".as_bytes())); + crash_if_err!(1, writer.write_all(b"\n")); } else { crash_if_err!(1, self.print_debug(settings, writer)); } @@ -1437,7 +1437,7 @@ mod tests { fn test_get_hash() { let a = "Ted".to_string(); - assert_eq!(2646829031758483623, get_hash(&a)); + assert_eq!(2_646_829_031_758_483_623, get_hash(&a)); } #[test] diff --git a/src/uucore/src/lib/lib.rs b/src/uucore/src/lib/lib.rs index c17f14516..e7f29e20c 100644 --- a/src/uucore/src/lib/lib.rs +++ b/src/uucore/src/lib/lib.rs @@ -146,15 +146,16 @@ pub trait Args: Iterator + Sized { InvalidEncodingHandling::Ignore => s.is_ok(), _ => true, }) - .map(|s| match s.is_ok() { - true => s.unwrap(), - false => s.unwrap_err(), + .map(|s| match s { + Ok(v) => v, + Err(e) => e, }) .collect(); - match full_conversion { - true => ConversionResult::Complete(result_vector), - false => ConversionResult::Lossy(result_vector), + if full_conversion { + ConversionResult::Complete(result_vector) + } else { + ConversionResult::Lossy(result_vector) } } diff --git a/src/uucore/src/lib/mods/backup_control.rs b/src/uucore/src/lib/mods/backup_control.rs index 6004ae84d..83268d351 100644 --- a/src/uucore/src/lib/mods/backup_control.rs +++ b/src/uucore/src/lib/mods/backup_control.rs @@ -33,7 +33,7 @@ pub fn determine_backup_suffix(supplied_suffix: Option<&str>) -> String { if let Some(suffix) = supplied_suffix { String::from(suffix) } else { - env::var("SIMPLE_BACKUP_SUFFIX").unwrap_or("~".to_owned()) + env::var("SIMPLE_BACKUP_SUFFIX").unwrap_or_else(|_| "~".to_owned()) } } From 714661774bd04d83f5c92c33ff2eef851f4c78a4 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sat, 29 May 2021 01:51:00 +0200 Subject: [PATCH 17/39] users: fix long_help text and clippy warning --- src/uu/users/src/users.rs | 21 +++++++++++++-------- tests/by-util/test_users.rs | 28 ++++++++++++---------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/uu/users/src/users.rs b/src/uu/users/src/users.rs index 4bb628441..99e06c1af 100644 --- a/src/uu/users/src/users.rs +++ b/src/uu/users/src/users.rs @@ -6,19 +6,14 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -/* last synced with: whoami (GNU coreutils) 8.22 */ -// Allow dead code here in order to keep all fields, constants here, for consistency. -#![allow(dead_code)] - #[macro_use] extern crate uucore; -use uucore::utmpx::*; - use clap::{App, Arg}; +use uucore::utmpx::{self, Utmpx}; -static ABOUT: &str = "Display who is currently logged in, according to FILE."; static VERSION: &str = env!("CARGO_PKG_VERSION"); +static ABOUT: &str = "Print the user names of users currently logged in to the current host"; static ARG_FILES: &str = "files"; @@ -26,13 +21,23 @@ fn get_usage() -> String { format!("{0} [FILE]", executable!()) } +fn get_long_usage() -> String { + format!( + "Output who is currently logged in according to FILE. +If FILE is not specified, use {}. /var/log/wtmp as FILE is common.", + utmpx::DEFAULT_FILE + ) +} + pub fn uumain(args: impl uucore::Args) -> i32 { let usage = get_usage(); + let after_help = get_long_usage(); let matches = App::new(executable!()) .version(VERSION) .about(ABOUT) .usage(&usage[..]) + .after_help(&after_help[..]) .arg(Arg::with_name(ARG_FILES).takes_value(true).max_values(1)) .get_matches_from(args); @@ -44,7 +49,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let filename = if !files.is_empty() { files[0].as_ref() } else { - DEFAULT_FILE + utmpx::DEFAULT_FILE }; let mut users = Utmpx::iter_all_records() diff --git a/tests/by-util/test_users.rs b/tests/by-util/test_users.rs index 3c5789820..89c3fdd0f 100644 --- a/tests/by-util/test_users.rs +++ b/tests/by-util/test_users.rs @@ -1,27 +1,23 @@ use crate::common::util::*; -use std::env; #[test] fn test_users_noarg() { new_ucmd!().succeeds(); } + #[test] +#[cfg(any(target_vendor = "apple", target_os = "linux"))] fn test_users_check_name() { - let result = TestScenario::new(util_name!()).ucmd_keepenv().succeeds(); + #[cfg(target_os = "linux")] + let util_name = util_name!(); + #[cfg(target_vendor = "apple")] + let util_name = format!("g{}", util_name!()); - // Expectation: USER is often set - let key = "USER"; + let expected = TestScenario::new(&util_name) + .cmd_keepenv(util_name) + .env("LANGUAGE", "C") + .succeeds() + .stdout_move_str(); - match env::var(key) { - Err(e) => println!("Key {} isn't set. Found {}", &key, e), - Ok(username) => - // Check if "users" contains the name of the user - { - println!("username found {}", &username); - // println!("result.stdout {}", &result.stdout); - if !result.stdout_str().is_empty() { - result.stdout_contains(&username); - } - } - } + new_ucmd!().succeeds().stdout_is(&expected); } From 52ea9c4a485f7e5c1a95d739dfa61aa2a1ce49c7 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sat, 29 May 2021 14:21:32 +0200 Subject: [PATCH 18/39] CI: set MSRV and "--target" for clippy * add "clippy.toml" in order to set MSRV for clippy linting this works only if clippy is invoked with "+nightly" * add "--target" to clippy in order to also lint tests --- .github/workflows/CICD.yml | 2 +- clippy.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 clippy.toml diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 804720bea..8bc106e34 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -94,7 +94,7 @@ jobs: run: | # `clippy` testing # * convert any warnings to GHA UI annotations; ref: - S=$(cargo clippy ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -- -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::warning file=\2,line=\3,col=\4::WARNING: \`cargo clippy\`: \1/p;" -e '}' ; } + S=$(cargo +nightly clippy --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -- -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::warning file=\2,line=\3,col=\4::WARNING: \`cargo clippy\`: \1/p;" -e '}' ; } min_version: name: MinRustV # Minimum supported rust version diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 000000000..0a0a69a41 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +msrv = "1.43.1" From fb812ff9d05c569c1b26ee0bb65a00a22e1a904b Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sat, 29 May 2021 14:29:46 +0200 Subject: [PATCH 19/39] Cargo.toml: remove factor_benches in order to be able to run clippy linting for all targets --- Cargo.lock | 316 +---------------------------------------------------- Cargo.toml | 3 +- 2 files changed, 6 insertions(+), 313 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 461ce5487..8f0b4efcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "Inflector" version = "0.11.4" @@ -43,12 +45,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "array-init" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6945cc5422176fc5e602e590c2878d2c2acd9a4fe20a4baa7c28022521698ec6" - [[package]] name = "arrayvec" version = "0.4.12" @@ -134,15 +130,8 @@ dependencies = [ "lazy_static", "memchr 2.4.0", "regex-automata", - "serde", ] -[[package]] -name = "bumpalo" -version = "3.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" - [[package]] name = "byte-tools" version = "0.2.0" @@ -155,15 +144,6 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" -[[package]] -name = "cast" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cdfa5d50aad6cb4d44dcab6101a7f79925bd59d82ca42f38a9856a28865374" -dependencies = [ - "rustc_version", -] - [[package]] name = "cc" version = "1.0.67" @@ -284,7 +264,6 @@ dependencies = [ "uu_expand", "uu_expr", "uu_factor", - "uu_factor_benches", "uu_false", "uu_fmt", "uu_fold", @@ -463,42 +442,6 @@ dependencies = [ "unicode-xid 0.0.4", ] -[[package]] -name = "criterion" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23" -dependencies = [ - "atty", - "cast", - "clap", - "criterion-plot", - "csv", - "itertools 0.10.0", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_cbor", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" -dependencies = [ - "cast", - "itertools 0.9.0", -] - [[package]] name = "crossbeam-channel" version = "0.5.1" @@ -544,28 +487,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr 2.4.0", -] - [[package]] name = "ctor" version = "0.1.20" @@ -807,15 +728,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.10.0" @@ -825,21 +737,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" - -[[package]] -name = "js-sys" -version = "0.3.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" -dependencies = [ - "wasm-bindgen", -] - [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1031,12 +928,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - [[package]] name = "ouroboros" version = "0.9.3" @@ -1088,15 +979,6 @@ dependencies = [ "proc-macro-hack", ] -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - [[package]] name = "pkg-config" version = "0.3.19" @@ -1113,34 +995,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "plotters" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590" - -[[package]] -name = "plotters-svg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211" -dependencies = [ - "plotters-backend", -] - [[package]] name = "ppv-lite86" version = "0.2.10" @@ -1446,21 +1300,6 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - [[package]] name = "same-file" version = "1.0.6" @@ -1482,16 +1321,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0", -] - -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser 0.10.2", + "semver-parser", ] [[package]] @@ -1500,53 +1330,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - -[[package]] -name = "serde" -version = "1.0.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" - -[[package]] -name = "serde_cbor" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" -dependencies = [ - "half", - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" -dependencies = [ - "proc-macro2", - "quote 1.0.9", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" -dependencies = [ - "itoa", - "ryu", - "serde", -] - [[package]] name = "sha1" version = "0.6.0" @@ -1737,28 +1520,12 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - [[package]] name = "typenum" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - [[package]] name = "unicode-segmentation" version = "1.7.1" @@ -2064,17 +1831,6 @@ dependencies = [ "uucore_procs", ] -[[package]] -name = "uu_factor_benches" -version = "0.0.0" -dependencies = [ - "array-init", - "criterion", - "rand 0.7.3", - "rand_chacha 0.2.2", - "uu_factor", -] - [[package]] name = "uu_false" version = "0.0.6" @@ -2553,7 +2309,7 @@ dependencies = [ "ouroboros", "rand 0.7.3", "rayon", - "semver 0.9.0", + "semver", "tempfile", "unicode-width", "uucore", @@ -2901,70 +2657,6 @@ version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" -[[package]] -name = "wasm-bindgen" -version = "0.2.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" -dependencies = [ - "cfg-if 1.0.0", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote 1.0.9", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" -dependencies = [ - "quote 1.0.9", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" -dependencies = [ - "proc-macro2", - "quote 1.0.9", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" - -[[package]] -name = "web-sys" -version = "0.3.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "wild" version = "2.0.4" diff --git a/Cargo.toml b/Cargo.toml index cc36199cc..36d667d98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -325,7 +325,8 @@ who = { optional=true, version="0.0.6", package="uu_who", path="src/uu/who" whoami = { optional=true, version="0.0.6", package="uu_whoami", path="src/uu/whoami" } yes = { optional=true, version="0.0.6", package="uu_yes", path="src/uu/yes" } -factor_benches = { optional = true, version = "0.0.0", package = "uu_factor_benches", path = "tests/benches/factor" } +# this breaks clippy linting with: "tests/by-util/test_factor_benches.rs: No such file or directory (os error 2)" +# factor_benches = { optional = true, version = "0.0.0", package = "uu_factor_benches", path = "tests/benches/factor" } # # * pinned transitive dependencies From 3aeccfd802f6c8edfbeda5cb31525326961b4b14 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sat, 29 May 2021 14:32:35 +0200 Subject: [PATCH 20/39] fix a lot of clippy warnings --- src/uu/basename/src/basename.rs | 3 +- src/uu/cp/src/cp.rs | 2 +- src/uu/factor/sieve.rs | 2 +- src/uu/head/src/parse.rs | 4 +- src/uu/install/src/install.rs | 1 + src/uu/ls/src/ls.rs | 1 + src/uu/sort/src/chunks.rs | 2 + src/uu/split/src/split.rs | 3 +- src/uu/sync/src/sync.rs | 1 + src/uu/test/src/parser.rs | 3 +- src/uu/touch/src/touch.rs | 9 +-- src/uu/tr/src/expand.rs | 2 +- src/uu/who/src/who.rs | 9 +-- src/uucore/src/lib/features/fsext.rs | 2 +- src/uucore/src/lib/features/process.rs | 1 + tests/by-util/test_base32.rs | 21 +++--- tests/by-util/test_base64.rs | 10 +-- tests/by-util/test_basename.rs | 17 +++-- tests/by-util/test_cat.rs | 23 ++++--- tests/by-util/test_chgrp.rs | 2 +- tests/by-util/test_chmod.rs | 12 +++- tests/by-util/test_chown.rs | 8 +-- tests/by-util/test_cksum.rs | 8 +-- tests/by-util/test_comm.rs | 2 +- tests/by-util/test_cp.rs | 4 +- tests/by-util/test_cut.rs | 16 ++--- tests/by-util/test_env.rs | 6 +- tests/by-util/test_factor.rs | 89 +++++++++++++------------- tests/by-util/test_head.rs | 2 +- tests/by-util/test_install.rs | 14 ++-- tests/by-util/test_ls.rs | 28 ++++---- tests/by-util/test_mkdir.rs | 14 ++-- tests/by-util/test_mktemp.rs | 20 +++--- tests/by-util/test_mv.rs | 2 +- tests/by-util/test_od.rs | 4 +- tests/by-util/test_paste.rs | 8 +-- tests/by-util/test_readlink.rs | 2 +- tests/by-util/test_relpath.rs | 1 + tests/by-util/test_shuf.rs | 22 +++---- tests/by-util/test_sort.rs | 10 +-- tests/by-util/test_split.rs | 9 +-- tests/by-util/test_stat.rs | 10 +-- tests/by-util/test_tail.rs | 26 ++++---- tests/by-util/test_touch.rs | 11 ++-- tests/by-util/test_truncate.rs | 4 +- tests/by-util/test_uniq.rs | 10 +-- tests/by-util/test_who.rs | 37 ++++++----- tests/common/util.rs | 22 +++---- 48 files changed, 269 insertions(+), 250 deletions(-) diff --git a/src/uu/basename/src/basename.rs b/src/uu/basename/src/basename.rs index e6476e436..ebd69de79 100644 --- a/src/uu/basename/src/basename.rs +++ b/src/uu/basename/src/basename.rs @@ -136,7 +136,8 @@ fn basename(fullname: &str, suffix: &str) -> String { } } -// can be replaced with strip_suffix once the minimum rust version is 1.45 +// can be replaced with strip_suffix once MSRV is 1.45 +#[allow(clippy::manual_strip)] fn strip_suffix(name: &str, suffix: &str) -> String { if name == suffix { return name.to_owned(); diff --git a/src/uu/cp/src/cp.rs b/src/uu/cp/src/cp.rs index 68ad3ed84..4d9e5965e 100644 --- a/src/uu/cp/src/cp.rs +++ b/src/uu/cp/src/cp.rs @@ -1108,7 +1108,7 @@ fn context_for(src: &Path, dest: &Path) -> String { /// Implements a simple backup copy for the destination file. /// TODO: for the backup, should this function be replaced by `copy_file(...)`? -fn backup_dest(dest: &Path, backup_path: &PathBuf) -> CopyResult { +fn backup_dest(dest: &Path, backup_path: &Path) -> CopyResult { fs::copy(dest, &backup_path)?; Ok(backup_path.into()) } diff --git a/src/uu/factor/sieve.rs b/src/uu/factor/sieve.rs index 41893699b..492c8159f 100644 --- a/src/uu/factor/sieve.rs +++ b/src/uu/factor/sieve.rs @@ -30,7 +30,7 @@ impl Iterator for Sieve { #[inline] fn next(&mut self) -> Option { - while let Some(n) = self.inner.next() { + for n in &mut self.inner { let mut prime = true; while let Some((next, inc)) = self.filts.peek() { // need to keep checking the min element of the heap diff --git a/src/uu/head/src/parse.rs b/src/uu/head/src/parse.rs index 470d821e0..0cf20be42 100644 --- a/src/uu/head/src/parse.rs +++ b/src/uu/head/src/parse.rs @@ -14,7 +14,7 @@ pub fn parse_obsolete(src: &str) -> Option let mut num_end = 0usize; let mut has_num = false; let mut last_char = 0 as char; - while let Some((n, c)) = chars.next() { + for (n, c) in &mut chars { if c.is_numeric() { has_num = true; num_end = n; @@ -109,7 +109,7 @@ pub fn parse_num(src: &str) -> Result<(usize, bool), ParseError> { let mut num_end = 0usize; let mut last_char = 0 as char; let mut num_count = 0usize; - while let Some((n, c)) = chars.next() { + for (n, c) in &mut chars { if c.is_numeric() { num_end = n; num_count += 1; diff --git a/src/uu/install/src/install.rs b/src/uu/install/src/install.rs index bb51a7606..7a4ad1fd1 100644 --- a/src/uu/install/src/install.rs +++ b/src/uu/install/src/install.rs @@ -520,6 +520,7 @@ fn copy_file_to_file(file: &Path, target: &Path, b: &Behavior) -> i32 { /// /// If the copy system call fails, we print a verbose error and return an empty error value. /// +#[allow(clippy::cognitive_complexity)] fn copy(from: &Path, to: &Path, b: &Behavior) -> Result<(), ()> { if b.compare && !need_copy(from, to, b) { return Ok(()); diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 17e0a16a8..60c076441 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -218,6 +218,7 @@ struct LongFormat { } impl Config { + #[allow(clippy::cognitive_complexity)] fn from(options: clap::ArgMatches) -> Config { let (mut format, opt) = if let Some(format_) = options.value_of(options::FORMAT) { ( diff --git a/src/uu/sort/src/chunks.rs b/src/uu/sort/src/chunks.rs index 6ec759211..23567833b 100644 --- a/src/uu/sort/src/chunks.rs +++ b/src/uu/sort/src/chunks.rs @@ -73,6 +73,7 @@ impl Chunk { /// * `lines`: The recycled vector to fill with lines. Must be empty. /// * `settings`: The global settings. #[allow(clippy::too_many_arguments)] +#[allow(clippy::borrowed_box)] pub fn read( sender_option: &mut Option>, mut buffer: Vec, @@ -164,6 +165,7 @@ fn parse_lines<'a>( /// The remaining bytes must be copied to the start of the buffer for the next invocation, /// if another invocation is necessary, which is determined by the other return value. /// * Whether this function should be called again. +#[allow(clippy::borrowed_box)] fn read_to_buffer( file: &mut Box, next_files: &mut impl Iterator>, diff --git a/src/uu/split/src/split.rs b/src/uu/split/src/split.rs index 726c9b8cd..39bd577cb 100644 --- a/src/uu/split/src/split.rs +++ b/src/uu/split/src/split.rs @@ -200,6 +200,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { split(&settings) } +#[allow(dead_code)] struct Settings { prefix: String, numeric_suffix: bool, @@ -210,7 +211,7 @@ struct Settings { filter: Option, strategy: String, strategy_param: String, - verbose: bool, + verbose: bool, // TODO: warning: field is never read: `verbose` } trait Splitter { diff --git a/src/uu/sync/src/sync.rs b/src/uu/sync/src/sync.rs index 985e7580d..59206db98 100644 --- a/src/uu/sync/src/sync.rs +++ b/src/uu/sync/src/sync.rs @@ -199,6 +199,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { } } + #[allow(clippy::if_same_then_else)] if matches.is_present(options::FILE_SYSTEM) { #[cfg(any(target_os = "linux", target_os = "windows"))] syncfs(files); diff --git a/src/uu/test/src/parser.rs b/src/uu/test/src/parser.rs index 0fcb25bd5..a77bfabb3 100644 --- a/src/uu/test/src/parser.rs +++ b/src/uu/test/src/parser.rs @@ -265,11 +265,10 @@ impl Parser { fn boolop(&mut self, op: Symbol) { if op == Symbol::BoolOp(OsString::from("-a")) { self.term(); - self.stack.push(op); } else { self.expr(); - self.stack.push(op); } + self.stack.push(op); } /// Parse a (possible) unary argument test (string length or file diff --git a/src/uu/touch/src/touch.rs b/src/uu/touch/src/touch.rs index b158fdc0e..00b936e55 100644 --- a/src/uu/touch/src/touch.rs +++ b/src/uu/touch/src/touch.rs @@ -145,14 +145,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 { || matches.is_present(options::sources::CURRENT) { let timestamp = if matches.is_present(options::sources::DATE) { - parse_date(matches.value_of(options::sources::DATE).unwrap().as_ref()) + parse_date(matches.value_of(options::sources::DATE).unwrap()) } else { - parse_timestamp( - matches - .value_of(options::sources::CURRENT) - .unwrap() - .as_ref(), - ) + parse_timestamp(matches.value_of(options::sources::CURRENT).unwrap()) }; (timestamp, timestamp) } else { diff --git a/src/uu/tr/src/expand.rs b/src/uu/tr/src/expand.rs index 73612a065..7d0c61c30 100644 --- a/src/uu/tr/src/expand.rs +++ b/src/uu/tr/src/expand.rs @@ -110,7 +110,7 @@ impl<'a> Iterator for ExpandSet<'a> { fn next(&mut self) -> Option { // while the Range has elements, try to return chars from it // but make sure that they actually turn out to be Chars! - while let Some(n) = self.range.next() { + for n in &mut self.range { if let Some(c) = from_u32(n) { return Some(c); } diff --git a/src/uu/who/src/who.rs b/src/uu/who/src/who.rs index 19ae3addb..2cddbf2d0 100644 --- a/src/uu/who/src/who.rs +++ b/src/uu/who/src/who.rs @@ -551,10 +551,11 @@ impl Who { " ?".into() }; - let mut s = ut.host(); - if self.do_lookup { - s = safe_unwrap!(ut.canon_host()); - } + let s = if self.do_lookup { + safe_unwrap!(ut.canon_host()) + } else { + ut.host() + }; let hoststr = if s.is_empty() { s } else { format!("({})", s) }; self.print_line( diff --git a/src/uucore/src/lib/features/fsext.rs b/src/uucore/src/lib/features/fsext.rs index 19c634b0b..6343ecd50 100644 --- a/src/uucore/src/lib/features/fsext.rs +++ b/src/uucore/src/lib/features/fsext.rs @@ -179,7 +179,7 @@ impl MountInfo { /* for Irix 6.5 */ | "ignore" => self.dummy = true, _ => self.dummy = self.fs_type == "none" - && self.mount_option.find(MOUNT_OPT_BIND).is_none(), + && !self.mount_option.contains(MOUNT_OPT_BIND) } // set MountInfo::remote #[cfg(windows)] diff --git a/src/uucore/src/lib/features/process.rs b/src/uucore/src/lib/features/process.rs index 078b782f5..975123cf7 100644 --- a/src/uucore/src/lib/features/process.rs +++ b/src/uucore/src/lib/features/process.rs @@ -40,6 +40,7 @@ pub enum ExitStatus { Signal(i32), } +#[allow(clippy::trivially_copy_pass_by_ref)] impl ExitStatus { fn from_std_status(status: StdExitStatus) -> Self { #[cfg(unix)] diff --git a/tests/by-util/test_base32.rs b/tests/by-util/test_base32.rs index e36c376be..788b85efa 100644 --- a/tests/by-util/test_base32.rs +++ b/tests/by-util/test_base32.rs @@ -34,7 +34,7 @@ fn test_base32_encode_file() { #[test] fn test_decode() { - for decode_param in vec!["-d", "--decode"] { + for decode_param in &["-d", "--decode"] { let input = "JBSWY3DPFQQFO33SNRSCC===\n"; new_ucmd!() .arg(decode_param) @@ -56,7 +56,7 @@ fn test_garbage() { #[test] fn test_ignore_garbage() { - for ignore_garbage_param in vec!["-i", "--ignore-garbage"] { + for ignore_garbage_param in &["-i", "--ignore-garbage"] { let input = "JBSWY\x013DPFQ\x02QFO33SNRSCC===\n"; new_ucmd!() .arg("-d") @@ -69,7 +69,7 @@ fn test_ignore_garbage() { #[test] fn test_wrap() { - for wrap_param in vec!["-w", "--wrap"] { + for wrap_param in &["-w", "--wrap"] { let input = "The quick brown fox jumps over the lazy dog."; new_ucmd!() .arg(wrap_param) @@ -84,16 +84,21 @@ fn test_wrap() { #[test] fn test_wrap_no_arg() { - for wrap_param in vec!["-w", "--wrap"] { - new_ucmd!().arg(wrap_param).fails().stderr_only(format!( - "error: The argument '--wrap \' requires a value but none was supplied\n\nUSAGE:\n base32 [OPTION]... [FILE]\n\nFor more information try --help" - )); + for wrap_param in &["-w", "--wrap"] { + let expected_stderr = "error: The argument '--wrap \' requires a value but none was \ + supplied\n\nUSAGE:\n base32 [OPTION]... [FILE]\n\nFor more \ + information try --help" + .to_string(); + new_ucmd!() + .arg(wrap_param) + .fails() + .stderr_only(expected_stderr); } } #[test] fn test_wrap_bad_arg() { - for wrap_param in vec!["-w", "--wrap"] { + for wrap_param in &["-w", "--wrap"] { new_ucmd!() .arg(wrap_param) .arg("b") diff --git a/tests/by-util/test_base64.rs b/tests/by-util/test_base64.rs index 89405d791..75445c933 100644 --- a/tests/by-util/test_base64.rs +++ b/tests/by-util/test_base64.rs @@ -26,7 +26,7 @@ fn test_base64_encode_file() { #[test] fn test_decode() { - for decode_param in vec!["-d", "--decode"] { + for decode_param in &["-d", "--decode"] { let input = "aGVsbG8sIHdvcmxkIQ=="; new_ucmd!() .arg(decode_param) @@ -48,7 +48,7 @@ fn test_garbage() { #[test] fn test_ignore_garbage() { - for ignore_garbage_param in vec!["-i", "--ignore-garbage"] { + for ignore_garbage_param in &["-i", "--ignore-garbage"] { let input = "aGVsbG8sIHdvcmxkIQ==\0"; new_ucmd!() .arg("-d") @@ -61,7 +61,7 @@ fn test_ignore_garbage() { #[test] fn test_wrap() { - for wrap_param in vec!["-w", "--wrap"] { + for wrap_param in &["-w", "--wrap"] { let input = "The quick brown fox jumps over the lazy dog."; new_ucmd!() .arg(wrap_param) @@ -74,7 +74,7 @@ fn test_wrap() { #[test] fn test_wrap_no_arg() { - for wrap_param in vec!["-w", "--wrap"] { + for wrap_param in &["-w", "--wrap"] { new_ucmd!().arg(wrap_param).fails().stderr_contains( &"The argument '--wrap ' requires a value but none was supplied", ); @@ -83,7 +83,7 @@ fn test_wrap_no_arg() { #[test] fn test_wrap_bad_arg() { - for wrap_param in vec!["-w", "--wrap"] { + for wrap_param in &["-w", "--wrap"] { new_ucmd!() .arg(wrap_param) .arg("b") diff --git a/tests/by-util/test_basename.rs b/tests/by-util/test_basename.rs index 1d26a922a..50d22b2eb 100644 --- a/tests/by-util/test_basename.rs +++ b/tests/by-util/test_basename.rs @@ -4,7 +4,7 @@ use std::ffi::OsStr; #[test] fn test_help() { - for help_flg in vec!["-h", "--help"] { + for help_flg in &["-h", "--help"] { new_ucmd!() .arg(&help_flg) .succeeds() @@ -15,7 +15,7 @@ fn test_help() { #[test] fn test_version() { - for version_flg in vec!["-V", "--version"] { + for version_flg in &["-V", "--version"] { assert!(new_ucmd!() .arg(&version_flg) .succeeds() @@ -59,7 +59,7 @@ fn test_dont_remove_suffix() { #[test] fn test_multiple_param() { - for multiple_param in vec!["-a", "--multiple"] { + for &multiple_param in &["-a", "--multiple"] { let path = "/foo/bar/baz"; new_ucmd!() .args(&[multiple_param, path, path]) @@ -70,7 +70,7 @@ fn test_multiple_param() { #[test] fn test_suffix_param() { - for suffix_param in vec!["-s", "--suffix"] { + for &suffix_param in &["-s", "--suffix"] { let path = "/foo/bar/baz.exe"; new_ucmd!() .args(&[suffix_param, ".exe", path, path]) @@ -81,7 +81,7 @@ fn test_suffix_param() { #[test] fn test_zero_param() { - for zero_param in vec!["-z", "--zero"] { + for &zero_param in &["-z", "--zero"] { let path = "/foo/bar/baz"; new_ucmd!() .args(&[zero_param, "-a", path, path]) @@ -91,7 +91,12 @@ fn test_zero_param() { } fn expect_error(input: Vec<&str>) { - assert!(new_ucmd!().args(&input).fails().no_stdout().stderr().len() > 0); + assert!(!new_ucmd!() + .args(&input) + .fails() + .no_stdout() + .stderr_str() + .is_empty()); } #[test] diff --git a/tests/by-util/test_cat.rs b/tests/by-util/test_cat.rs index adda905b3..8ea5bbaae 100644 --- a/tests/by-util/test_cat.rs +++ b/tests/by-util/test_cat.rs @@ -237,7 +237,7 @@ fn test_numbered_lines_no_trailing_newline() { #[test] fn test_stdin_show_nonprinting() { - for same_param in vec!["-v", "--show-nonprinting"] { + for same_param in &["-v", "--show-nonprinting"] { new_ucmd!() .args(&[same_param]) .pipe_in("\t\0\n") @@ -248,7 +248,7 @@ fn test_stdin_show_nonprinting() { #[test] fn test_stdin_show_tabs() { - for same_param in vec!["-T", "--show-tabs"] { + for same_param in &["-T", "--show-tabs"] { new_ucmd!() .args(&[same_param]) .pipe_in("\t\0\n") @@ -259,7 +259,7 @@ fn test_stdin_show_tabs() { #[test] fn test_stdin_show_ends() { - for same_param in vec!["-E", "--show-ends"] { + for &same_param in &["-E", "--show-ends"] { new_ucmd!() .args(&[same_param, "-"]) .pipe_in("\t\0\n\t") @@ -270,7 +270,7 @@ fn test_stdin_show_ends() { #[test] fn test_stdin_show_all() { - for same_param in vec!["-A", "--show-all"] { + for same_param in &["-A", "--show-all"] { new_ucmd!() .args(&[same_param]) .pipe_in("\t\0\n") @@ -299,7 +299,7 @@ fn test_stdin_nonprinting_and_tabs() { #[test] fn test_stdin_squeeze_blank() { - for same_param in vec!["-s", "--squeeze-blank"] { + for same_param in &["-s", "--squeeze-blank"] { new_ucmd!() .arg(same_param) .pipe_in("\n\na\n\n\n\n\nb\n\n\n") @@ -310,7 +310,7 @@ fn test_stdin_squeeze_blank() { #[test] fn test_stdin_number_non_blank() { - for same_param in vec!["-b", "--number-nonblank"] { + for same_param in &["-b", "--number-nonblank"] { new_ucmd!() .arg(same_param) .arg("-") @@ -322,7 +322,7 @@ fn test_stdin_number_non_blank() { #[test] fn test_non_blank_overrides_number() { - for same_param in vec!["-b", "--number-nonblank"] { + for &same_param in &["-b", "--number-nonblank"] { new_ucmd!() .args(&[same_param, "-"]) .pipe_in("\na\nb\n\n\nc") @@ -333,7 +333,7 @@ fn test_non_blank_overrides_number() { #[test] fn test_squeeze_blank_before_numbering() { - for same_param in vec!["-s", "--squeeze-blank"] { + for &same_param in &["-s", "--squeeze-blank"] { new_ucmd!() .args(&[same_param, "-n", "-"]) .pipe_in("a\n\n\nb") @@ -408,7 +408,10 @@ fn test_domain_socket() { use std::thread; use unix_socket::UnixListener; - let dir = tempfile::Builder::new().prefix("unix_socket").tempdir().expect("failed to create dir"); + let dir = tempfile::Builder::new() + .prefix("unix_socket") + .tempdir() + .expect("failed to create dir"); let socket_path = dir.path().join("sock"); let listener = UnixListener::bind(&socket_path).expect("failed to create socket"); @@ -426,7 +429,7 @@ fn test_domain_socket() { let child = new_ucmd!().args(&[socket_path]).run_no_wait(); barrier.wait(); - let stdout = &child.wait_with_output().unwrap().stdout.clone(); + let stdout = &child.wait_with_output().unwrap().stdout; let output = String::from_utf8_lossy(&stdout); assert_eq!("a\tb", output); diff --git a/tests/by-util/test_chgrp.rs b/tests/by-util/test_chgrp.rs index a7848b1b6..c0fc503ae 100644 --- a/tests/by-util/test_chgrp.rs +++ b/tests/by-util/test_chgrp.rs @@ -6,7 +6,7 @@ fn test_invalid_option() { new_ucmd!().arg("-w").arg("/").fails(); } -static DIR: &'static str = "/tmp"; +static DIR: &str = "/tmp"; #[test] fn test_invalid_group() { diff --git a/tests/by-util/test_chmod.rs b/tests/by-util/test_chmod.rs index f20429a6e..4611d1b96 100644 --- a/tests/by-util/test_chmod.rs +++ b/tests/by-util/test_chmod.rs @@ -8,8 +8,8 @@ use self::chmod::strip_minus_from_mode; extern crate chmod; use self::libc::umask; -static TEST_FILE: &'static str = "file"; -static REFERENCE_FILE: &'static str = "reference"; +static TEST_FILE: &str = "file"; +static REFERENCE_FILE: &str = "reference"; static REFERENCE_PERMS: u32 = 0o247; lazy_static! { static ref UMASK_MUTEX: Mutex<()> = Mutex::new(()); @@ -69,6 +69,7 @@ fn run_tests(tests: Vec) { } #[test] +#[allow(clippy::unreadable_literal)] fn test_chmod_octal() { let tests = vec![ TestCase { @@ -121,6 +122,7 @@ fn test_chmod_octal() { } #[test] +#[allow(clippy::unreadable_literal)] fn test_chmod_ugoa() { let _guard = UMASK_MUTEX.lock(); @@ -216,6 +218,7 @@ fn test_chmod_ugoa() { } #[test] +#[allow(clippy::unreadable_literal)] fn test_chmod_ugo_copy() { let tests = vec![ TestCase { @@ -248,6 +251,7 @@ fn test_chmod_ugo_copy() { } #[test] +#[allow(clippy::unreadable_literal)] fn test_chmod_many_options() { let _guard = UMASK_MUTEX.lock(); @@ -264,6 +268,7 @@ fn test_chmod_many_options() { } #[test] +#[allow(clippy::unreadable_literal)] fn test_chmod_reference_file() { let tests = vec![ TestCase { @@ -303,6 +308,7 @@ fn test_permission_denied() { } #[test] +#[allow(clippy::unreadable_literal)] fn test_chmod_recursive() { let _guard = UMASK_MUTEX.lock(); @@ -477,7 +483,7 @@ fn test_chmod_strip_minus_from_mode() { ]; for test in tests { - let mut args: Vec = test.0.split(" ").map(|v| v.to_string()).collect(); + let mut args: Vec = test.0.split(' ').map(|v| v.to_string()).collect(); let _mode_had_minus_prefix = strip_minus_from_mode(&mut args); assert_eq!(test.1, args.join(" ")); } diff --git a/tests/by-util/test_chown.rs b/tests/by-util/test_chown.rs index 3d94632a6..a531fc7f3 100644 --- a/tests/by-util/test_chown.rs +++ b/tests/by-util/test_chown.rs @@ -39,7 +39,7 @@ mod test_passgrp { #[test] fn test_usr2uid() { assert_eq!(0, usr2uid("root").unwrap()); - assert!(usr2uid("88888888").is_err()); + assert!(usr2uid("88_888_888").is_err()); assert!(usr2uid("auserthatdoesntexist").is_err()); } @@ -50,14 +50,14 @@ mod test_passgrp { } else { assert_eq!(0, grp2gid("wheel").unwrap()); } - assert!(grp2gid("88888888").is_err()); + assert!(grp2gid("88_888_888").is_err()); assert!(grp2gid("agroupthatdoesntexist").is_err()); } #[test] fn test_uid2usr() { assert_eq!("root", uid2usr(0).unwrap()); - assert!(uid2usr(88888888).is_err()); + assert!(uid2usr(88_888_888).is_err()); } #[test] @@ -67,7 +67,7 @@ mod test_passgrp { } else { assert_eq!("wheel", gid2grp(0).unwrap()); } - assert!(gid2grp(88888888).is_err()); + assert!(gid2grp(88_888_888).is_err()); } } diff --git a/tests/by-util/test_cksum.rs b/tests/by-util/test_cksum.rs index 81ef4c177..0fd028781 100644 --- a/tests/by-util/test_cksum.rs +++ b/tests/by-util/test_cksum.rs @@ -85,12 +85,12 @@ fn test_crc_for_bigger_than_32_bytes() { let result = ucmd.arg("chars.txt").succeeds(); - let mut stdout_splitted = result.stdout_str().split(" "); + let mut stdout_splitted = result.stdout_str().split(' '); let cksum: i64 = stdout_splitted.next().unwrap().parse().unwrap(); let bytes_cnt: i64 = stdout_splitted.next().unwrap().parse().unwrap(); - assert_eq!(cksum, 586047089); + assert_eq!(cksum, 586_047_089); assert_eq!(bytes_cnt, 16); } @@ -100,11 +100,11 @@ fn test_stdin_larger_than_128_bytes() { let result = ucmd.arg("larger_than_2056_bytes.txt").succeeds(); - let mut stdout_splitted = result.stdout_str().split(" "); + let mut stdout_splitted = result.stdout_str().split(' '); let cksum: i64 = stdout_splitted.next().unwrap().parse().unwrap(); let bytes_cnt: i64 = stdout_splitted.next().unwrap().parse().unwrap(); - assert_eq!(cksum, 945881979); + assert_eq!(cksum, 945_881_979); assert_eq!(bytes_cnt, 2058); } diff --git a/tests/by-util/test_comm.rs b/tests/by-util/test_comm.rs index 23aeb8309..fa8c8beca 100644 --- a/tests/by-util/test_comm.rs +++ b/tests/by-util/test_comm.rs @@ -74,7 +74,7 @@ fn output_delimiter_require_arg() { #[cfg_attr(not(feature = "test_unimplemented"), ignore)] #[test] fn zero_terminated() { - for param in vec!["-z", "--zero-terminated"] { + for ¶m in &["-z", "--zero-terminated"] { new_ucmd!() .args(&[param, "a", "b"]) .fails() diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index d49219b04..e4d7fdea7 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -108,7 +108,7 @@ fn test_cp_multiple_files() { #[test] // FixME: for MacOS, this has intermittent failures; track repair progress at GH:uutils/coreutils/issues/1590 -#[cfg(not(macos))] +#[cfg(not(target_os = "macos"))] fn test_cp_recurse() { let (at, mut ucmd) = at_and_ucmd!(); ucmd.arg("-r") @@ -132,7 +132,7 @@ fn test_cp_with_dirs_t() { #[test] // FixME: for MacOS, this has intermittent failures; track repair progress at GH:uutils/coreutils/issues/1590 -#[cfg(not(macos))] +#[cfg(not(target_os = "macos"))] fn test_cp_with_dirs() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; diff --git a/tests/by-util/test_cut.rs b/tests/by-util/test_cut.rs index 413b73154..8f81b94c1 100644 --- a/tests/by-util/test_cut.rs +++ b/tests/by-util/test_cut.rs @@ -1,13 +1,13 @@ use crate::common::util::*; -static INPUT: &'static str = "lists.txt"; +static INPUT: &str = "lists.txt"; struct TestedSequence<'b> { name: &'b str, sequence: &'b str, } -static EXAMPLE_SEQUENCES: &'static [TestedSequence<'static>] = &[ +static EXAMPLE_SEQUENCES: &[TestedSequence] = &[ TestedSequence { name: "singular", sequence: "2", @@ -34,14 +34,14 @@ static EXAMPLE_SEQUENCES: &'static [TestedSequence<'static>] = &[ }, ]; -static COMPLEX_SEQUENCE: &'static TestedSequence<'static> = &TestedSequence { +static COMPLEX_SEQUENCE: &TestedSequence = &TestedSequence { name: "", sequence: "9-,6-7,-2,4", }; #[test] fn test_byte_sequence() { - for param in vec!["-b", "--bytes"] { + for ¶m in &["-b", "--bytes"] { for example_seq in EXAMPLE_SEQUENCES { new_ucmd!() .args(&[param, example_seq.sequence, INPUT]) @@ -53,7 +53,7 @@ fn test_byte_sequence() { #[test] fn test_char_sequence() { - for param in vec!["-c", "--characters"] { + for ¶m in &["-c", "--characters"] { for example_seq in EXAMPLE_SEQUENCES { //as of coreutils 8.25 a char range is effectively the same as a byte range; there is no distinct treatment of utf8 chars. new_ucmd!() @@ -66,7 +66,7 @@ fn test_char_sequence() { #[test] fn test_field_sequence() { - for param in vec!["-f", "--fields"] { + for ¶m in &["-f", "--fields"] { for example_seq in EXAMPLE_SEQUENCES { new_ucmd!() .args(&[param, example_seq.sequence, INPUT]) @@ -78,7 +78,7 @@ fn test_field_sequence() { #[test] fn test_specify_delimiter() { - for param in vec!["-d", "--delimiter"] { + for ¶m in &["-d", "--delimiter"] { new_ucmd!() .args(&[param, ":", "-f", COMPLEX_SEQUENCE.sequence, INPUT]) .succeeds() @@ -122,7 +122,7 @@ fn test_zero_terminated() { #[test] fn test_only_delimited() { - for param in vec!["-s", "--only-delimited"] { + for param in &["-s", "--only-delimited"] { new_ucmd!() .args(&["-d_", param, "-f", "1"]) .pipe_in("91\n82\n7_3") diff --git a/tests/by-util/test_env.rs b/tests/by-util/test_env.rs index e86a41783..23bba57a9 100644 --- a/tests/by-util/test_env.rs +++ b/tests/by-util/test_env.rs @@ -118,7 +118,7 @@ fn test_null_delimiter() { let mut vars: Vec<_> = out.split('\0').collect(); assert_eq!(vars.len(), 3); - vars.sort(); + vars.sort_unstable(); assert_eq!(vars[0], ""); assert_eq!(vars[1], "ABC=xyz"); assert_eq!(vars[2], "FOO=bar"); @@ -135,7 +135,7 @@ fn test_unset_variable() { .succeeds() .stdout_move_str(); - assert_eq!(out.lines().any(|line| line.starts_with("HOME=")), false); + assert!(!out.lines().any(|line| line.starts_with("HOME="))); } #[test] @@ -196,7 +196,7 @@ fn test_change_directory() { fn test_fail_change_directory() { let scene = TestScenario::new(util_name!()); let some_non_existing_path = "some_nonexistent_path"; - assert_eq!(Path::new(some_non_existing_path).is_dir(), false); + assert!(!Path::new(some_non_existing_path).is_dir()); let out = scene .ucmd() diff --git a/tests/by-util/test_factor.rs b/tests/by-util/test_factor.rs index af2ff4ddb..963b82ed8 100644 --- a/tests/by-util/test_factor.rs +++ b/tests/by-util/test_factor.rs @@ -4,6 +4,7 @@ // // For the full copyright and license information, please view the LICENSE file // that was distributed with this source code. +#![allow(clippy::unreadable_literal)] use crate::common::util::*; use std::time::SystemTime; @@ -77,7 +78,7 @@ fn test_random() { }; } - factors.sort(); + factors.sort_unstable(); (product, factors) }; @@ -92,7 +93,7 @@ fn test_random() { for factor in factors { outstring.push_str(&(format!(" {}", factor))[..]); } - outstring.push_str("\n"); + outstring.push('\n'); } run(instring.as_bytes(), outstring.as_bytes()); @@ -131,7 +132,7 @@ fn test_random_big() { f_bits.push(extrarange.sample(&mut rng)); } f_bits.push(extrabits); - f_bits.sort(); + f_bits.sort_unstable(); // compute sequential differences here. We leave off the +14 bits // so we can just index PRIMES_BY_BITS @@ -160,7 +161,7 @@ fn test_random_big() { } assert_eq!(nbits, 64); - factors.sort(); + factors.sort_unstable(); (product, factors) }; @@ -174,7 +175,7 @@ fn test_random_big() { for factor in factors { outstring.push_str(&(format!(" {}", factor))[..]); } - outstring.push_str("\n"); + outstring.push('\n'); } run(instring.as_bytes(), outstring.as_bytes()); @@ -202,7 +203,7 @@ fn run(instring: &[u8], outstring: &[u8]) { .stdout_is(String::from_utf8(outstring.to_owned()).unwrap()); } -const PRIMES_BY_BITS: &'static [&'static [u64]] = &[ +const PRIMES_BY_BITS: &[&[u64]] = &[ PRIMES14, PRIMES15, PRIMES16, PRIMES17, PRIMES18, PRIMES19, PRIMES20, PRIMES21, PRIMES22, PRIMES23, PRIMES24, PRIMES25, PRIMES26, PRIMES27, PRIMES28, PRIMES29, PRIMES30, PRIMES31, PRIMES32, PRIMES33, PRIMES34, PRIMES35, PRIMES36, PRIMES37, PRIMES38, PRIMES39, PRIMES40, @@ -210,7 +211,7 @@ const PRIMES_BY_BITS: &'static [&'static [u64]] = &[ PRIMES50, ]; -const PRIMES64: &'static [u64] = &[ +const PRIMES64: &[u64] = &[ 18446744073709551557, 18446744073709551533, 18446744073709551521, @@ -262,7 +263,7 @@ const PRIMES64: &'static [u64] = &[ 18446744073709549571, ]; -const PRIMES14: &'static [u64] = &[ +const PRIMES14: &[u64] = &[ 16381, 16369, 16363, 16361, 16349, 16339, 16333, 16319, 16301, 16273, 16267, 16253, 16249, 16231, 16229, 16223, 16217, 16193, 16189, 16187, 16183, 16141, 16139, 16127, 16111, 16103, 16097, 16091, 16087, 16073, 16069, 16067, 16063, 16061, 16057, 16033, 16007, 16001, 15991, @@ -274,7 +275,7 @@ const PRIMES14: &'static [u64] = &[ 15373, ]; -const PRIMES15: &'static [u64] = &[ +const PRIMES15: &[u64] = &[ 32749, 32719, 32717, 32713, 32707, 32693, 32687, 32653, 32647, 32633, 32621, 32611, 32609, 32603, 32587, 32579, 32573, 32569, 32563, 32561, 32537, 32533, 32531, 32507, 32503, 32497, 32491, 32479, 32467, 32443, 32441, 32429, 32423, 32413, 32411, 32401, 32381, 32377, 32371, @@ -285,7 +286,7 @@ const PRIMES15: &'static [u64] = &[ 31847, 31817, 31799, 31793, 31771, 31769, 31751, ]; -const PRIMES16: &'static [u64] = &[ +const PRIMES16: &[u64] = &[ 65521, 65519, 65497, 65479, 65449, 65447, 65437, 65423, 65419, 65413, 65407, 65393, 65381, 65371, 65357, 65353, 65327, 65323, 65309, 65293, 65287, 65269, 65267, 65257, 65239, 65213, 65203, 65183, 65179, 65173, 65171, 65167, 65147, 65141, 65129, 65123, 65119, 65111, 65101, @@ -295,7 +296,7 @@ const PRIMES16: &'static [u64] = &[ 64627, 64621, 64613, 64609, 64601, 64591, 64579, 64577, 64567, 64553, ]; -const PRIMES17: &'static [u64] = &[ +const PRIMES17: &[u64] = &[ 131071, 131063, 131059, 131041, 131023, 131011, 131009, 130987, 130981, 130973, 130969, 130957, 130927, 130873, 130859, 130843, 130841, 130829, 130817, 130811, 130807, 130787, 130783, 130769, 130729, 130699, 130693, 130687, 130681, 130657, 130651, 130649, 130643, 130639, 130633, 130631, @@ -306,7 +307,7 @@ const PRIMES17: &'static [u64] = &[ 130073, 130069, 130057, 130051, ]; -const PRIMES18: &'static [u64] = &[ +const PRIMES18: &[u64] = &[ 262139, 262133, 262127, 262121, 262111, 262109, 262103, 262079, 262069, 262051, 262049, 262027, 262007, 261983, 261977, 261973, 261971, 261959, 261917, 261887, 261881, 261847, 261823, 261799, 261791, 261787, 261773, 261761, 261757, 261739, 261721, 261713, 261707, 261697, 261673, 261643, @@ -316,7 +317,7 @@ const PRIMES18: &'static [u64] = &[ 261169, 261167, 261127, ]; -const PRIMES19: &'static [u64] = &[ +const PRIMES19: &[u64] = &[ 524287, 524269, 524261, 524257, 524243, 524231, 524221, 524219, 524203, 524201, 524197, 524189, 524171, 524149, 524123, 524119, 524113, 524099, 524087, 524081, 524071, 524063, 524057, 524053, 524047, 523997, 523987, 523969, 523949, 523937, 523927, 523907, 523903, 523877, 523867, 523847, @@ -326,7 +327,7 @@ const PRIMES19: &'static [u64] = &[ 523403, 523387, 523357, 523351, 523349, 523333, 523307, 523297, ]; -const PRIMES20: &'static [u64] = &[ +const PRIMES20: &[u64] = &[ 1048573, 1048571, 1048559, 1048549, 1048517, 1048507, 1048447, 1048433, 1048423, 1048391, 1048387, 1048367, 1048361, 1048357, 1048343, 1048309, 1048291, 1048273, 1048261, 1048219, 1048217, 1048213, 1048193, 1048189, 1048139, 1048129, 1048127, 1048123, 1048063, 1048051, @@ -336,7 +337,7 @@ const PRIMES20: &'static [u64] = &[ 1047691, 1047689, 1047671, 1047667, 1047653, 1047649, 1047647, 1047589, 1047587, 1047559, ]; -const PRIMES21: &'static [u64] = &[ +const PRIMES21: &[u64] = &[ 2097143, 2097133, 2097131, 2097097, 2097091, 2097083, 2097047, 2097041, 2097031, 2097023, 2097013, 2096993, 2096987, 2096971, 2096959, 2096957, 2096947, 2096923, 2096911, 2096909, 2096893, 2096881, 2096873, 2096867, 2096851, 2096837, 2096807, 2096791, 2096789, 2096777, @@ -346,7 +347,7 @@ const PRIMES21: &'static [u64] = &[ 2096221, 2096209, 2096191, 2096183, 2096147, ]; -const PRIMES22: &'static [u64] = &[ +const PRIMES22: &[u64] = &[ 4194301, 4194287, 4194277, 4194271, 4194247, 4194217, 4194199, 4194191, 4194187, 4194181, 4194173, 4194167, 4194143, 4194137, 4194131, 4194107, 4194103, 4194023, 4194011, 4194007, 4193977, 4193971, 4193963, 4193957, 4193939, 4193929, 4193909, 4193869, 4193807, 4193803, @@ -356,7 +357,7 @@ const PRIMES22: &'static [u64] = &[ 4193297, ]; -const PRIMES23: &'static [u64] = &[ +const PRIMES23: &[u64] = &[ 8388593, 8388587, 8388581, 8388571, 8388547, 8388539, 8388473, 8388461, 8388451, 8388449, 8388439, 8388427, 8388421, 8388409, 8388377, 8388371, 8388319, 8388301, 8388287, 8388283, 8388277, 8388239, 8388209, 8388187, 8388113, 8388109, 8388091, 8388071, 8388059, 8388019, @@ -365,7 +366,7 @@ const PRIMES23: &'static [u64] = &[ 8387723, 8387707, 8387671, 8387611, 8387609, 8387591, ]; -const PRIMES24: &'static [u64] = &[ +const PRIMES24: &[u64] = &[ 16777213, 16777199, 16777183, 16777153, 16777141, 16777139, 16777127, 16777121, 16777099, 16777049, 16777027, 16776989, 16776973, 16776971, 16776967, 16776961, 16776941, 16776937, 16776931, 16776919, 16776901, 16776899, 16776869, 16776857, 16776839, 16776833, 16776817, @@ -375,7 +376,7 @@ const PRIMES24: &'static [u64] = &[ 16776317, 16776313, 16776289, 16776217, 16776211, ]; -const PRIMES25: &'static [u64] = &[ +const PRIMES25: &[u64] = &[ 33554393, 33554383, 33554371, 33554347, 33554341, 33554317, 33554291, 33554273, 33554267, 33554249, 33554239, 33554221, 33554201, 33554167, 33554159, 33554137, 33554123, 33554093, 33554083, 33554077, 33554051, 33554021, 33554011, 33554009, 33553999, 33553991, 33553969, @@ -385,7 +386,7 @@ const PRIMES25: &'static [u64] = &[ 33553519, 33553517, 33553511, 33553489, 33553463, 33553451, 33553417, ]; -const PRIMES26: &'static [u64] = &[ +const PRIMES26: &[u64] = &[ 67108859, 67108837, 67108819, 67108777, 67108763, 67108757, 67108753, 67108747, 67108739, 67108729, 67108721, 67108709, 67108693, 67108669, 67108667, 67108661, 67108649, 67108633, 67108597, 67108579, 67108529, 67108511, 67108507, 67108493, 67108471, 67108463, 67108453, @@ -396,7 +397,7 @@ const PRIMES26: &'static [u64] = &[ 67107863, ]; -const PRIMES27: &'static [u64] = &[ +const PRIMES27: &[u64] = &[ 134217689, 134217649, 134217617, 134217613, 134217593, 134217541, 134217529, 134217509, 134217497, 134217493, 134217487, 134217467, 134217439, 134217437, 134217409, 134217403, 134217401, 134217367, 134217361, 134217353, 134217323, 134217301, 134217277, 134217257, @@ -407,7 +408,7 @@ const PRIMES27: &'static [u64] = &[ 134216737, 134216729, ]; -const PRIMES28: &'static [u64] = &[ +const PRIMES28: &[u64] = &[ 268435399, 268435367, 268435361, 268435337, 268435331, 268435313, 268435291, 268435273, 268435243, 268435183, 268435171, 268435157, 268435147, 268435133, 268435129, 268435121, 268435109, 268435091, 268435067, 268435043, 268435039, 268435033, 268435019, 268435009, @@ -418,7 +419,7 @@ const PRIMES28: &'static [u64] = &[ 268434479, 268434461, ]; -const PRIMES29: &'static [u64] = &[ +const PRIMES29: &[u64] = &[ 536870909, 536870879, 536870869, 536870849, 536870839, 536870837, 536870819, 536870813, 536870791, 536870779, 536870767, 536870743, 536870729, 536870723, 536870717, 536870701, 536870683, 536870657, 536870641, 536870627, 536870611, 536870603, 536870599, 536870573, @@ -428,7 +429,7 @@ const PRIMES29: &'static [u64] = &[ 536870027, 536869999, 536869951, 536869943, 536869937, 536869919, 536869901, 536869891, ]; -const PRIMES30: &'static [u64] = &[ +const PRIMES30: &[u64] = &[ 1073741789, 1073741783, 1073741741, 1073741723, 1073741719, 1073741717, 1073741689, 1073741671, 1073741663, 1073741651, 1073741621, 1073741567, 1073741561, 1073741527, 1073741503, 1073741477, 1073741467, 1073741441, 1073741419, 1073741399, 1073741387, 1073741381, 1073741371, 1073741329, @@ -437,7 +438,7 @@ const PRIMES30: &'static [u64] = &[ 1073740853, 1073740847, 1073740819, 1073740807, ]; -const PRIMES31: &'static [u64] = &[ +const PRIMES31: &[u64] = &[ 2147483647, 2147483629, 2147483587, 2147483579, 2147483563, 2147483549, 2147483543, 2147483497, 2147483489, 2147483477, 2147483423, 2147483399, 2147483353, 2147483323, 2147483269, 2147483249, 2147483237, 2147483179, 2147483171, 2147483137, 2147483123, 2147483077, 2147483069, 2147483059, @@ -446,7 +447,7 @@ const PRIMES31: &'static [u64] = &[ 2147482763, 2147482739, 2147482697, 2147482693, 2147482681, 2147482663, 2147482661, ]; -const PRIMES32: &'static [u64] = &[ +const PRIMES32: &[u64] = &[ 4294967291, 4294967279, 4294967231, 4294967197, 4294967189, 4294967161, 4294967143, 4294967111, 4294967087, 4294967029, 4294966997, 4294966981, 4294966943, 4294966927, 4294966909, 4294966877, 4294966829, 4294966813, 4294966769, 4294966667, 4294966661, 4294966657, 4294966651, 4294966639, @@ -454,7 +455,7 @@ const PRIMES32: &'static [u64] = &[ 4294966373, 4294966367, 4294966337, 4294966297, ]; -const PRIMES33: &'static [u64] = &[ +const PRIMES33: &[u64] = &[ 8589934583, 8589934567, 8589934543, 8589934513, 8589934487, 8589934307, 8589934291, 8589934289, 8589934271, 8589934237, 8589934211, 8589934207, 8589934201, 8589934187, 8589934151, 8589934141, 8589934139, 8589934117, 8589934103, 8589934099, 8589934091, 8589934069, 8589934049, 8589934027, @@ -463,7 +464,7 @@ const PRIMES33: &'static [u64] = &[ 8589933647, 8589933641, 8589933637, 8589933631, 8589933629, 8589933619, 8589933601, 8589933581, ]; -const PRIMES34: &'static [u64] = &[ +const PRIMES34: &[u64] = &[ 17179869143, 17179869107, 17179869071, @@ -514,7 +515,7 @@ const PRIMES34: &'static [u64] = &[ 17179868183, ]; -const PRIMES35: &'static [u64] = &[ +const PRIMES35: &[u64] = &[ 34359738337, 34359738319, 34359738307, @@ -547,7 +548,7 @@ const PRIMES35: &'static [u64] = &[ 34359737371, ]; -const PRIMES36: &'static [u64] = &[ +const PRIMES36: &[u64] = &[ 68719476731, 68719476719, 68719476713, @@ -599,7 +600,7 @@ const PRIMES36: &'static [u64] = &[ 68719475729, ]; -const PRIMES37: &'static [u64] = &[ +const PRIMES37: &[u64] = &[ 137438953447, 137438953441, 137438953427, @@ -625,7 +626,7 @@ const PRIMES37: &'static [u64] = &[ 137438952491, ]; -const PRIMES38: &'static [u64] = &[ +const PRIMES38: &[u64] = &[ 274877906899, 274877906857, 274877906837, @@ -665,7 +666,7 @@ const PRIMES38: &'static [u64] = &[ 274877905931, ]; -const PRIMES39: &'static [u64] = &[ +const PRIMES39: &[u64] = &[ 549755813881, 549755813869, 549755813821, @@ -711,7 +712,7 @@ const PRIMES39: &'static [u64] = &[ 549755812867, ]; -const PRIMES40: &'static [u64] = &[ +const PRIMES40: &[u64] = &[ 1099511627689, 1099511627609, 1099511627581, @@ -741,7 +742,7 @@ const PRIMES40: &'static [u64] = &[ 1099511626771, ]; -const PRIMES41: &'static [u64] = &[ +const PRIMES41: &[u64] = &[ 2199023255531, 2199023255521, 2199023255497, @@ -780,7 +781,7 @@ const PRIMES41: &'static [u64] = &[ 2199023254567, ]; -const PRIMES42: &'static [u64] = &[ +const PRIMES42: &[u64] = &[ 4398046511093, 4398046511087, 4398046511071, @@ -820,7 +821,7 @@ const PRIMES42: &'static [u64] = &[ 4398046510093, ]; -const PRIMES43: &'static [u64] = &[ +const PRIMES43: &[u64] = &[ 8796093022151, 8796093022141, 8796093022091, @@ -855,7 +856,7 @@ const PRIMES43: &'static [u64] = &[ 8796093021269, ]; -const PRIMES44: &'static [u64] = &[ +const PRIMES44: &[u64] = &[ 17592186044399, 17592186044299, 17592186044297, @@ -888,7 +889,7 @@ const PRIMES44: &'static [u64] = &[ 17592186043409, ]; -const PRIMES45: &'static [u64] = &[ +const PRIMES45: &[u64] = &[ 35184372088777, 35184372088763, 35184372088751, @@ -929,7 +930,7 @@ const PRIMES45: &'static [u64] = &[ 35184372087869, ]; -const PRIMES46: &'static [u64] = &[ +const PRIMES46: &[u64] = &[ 70368744177643, 70368744177607, 70368744177601, @@ -964,7 +965,7 @@ const PRIMES46: &'static [u64] = &[ 70368744176711, ]; -const PRIMES47: &'static [u64] = &[ +const PRIMES47: &[u64] = &[ 140737488355213, 140737488355201, 140737488355181, @@ -986,7 +987,7 @@ const PRIMES47: &'static [u64] = &[ 140737488354329, ]; -const PRIMES48: &'static [u64] = &[ +const PRIMES48: &[u64] = &[ 281474976710597, 281474976710591, 281474976710567, @@ -1019,7 +1020,7 @@ const PRIMES48: &'static [u64] = &[ 281474976709637, ]; -const PRIMES49: &'static [u64] = &[ +const PRIMES49: &[u64] = &[ 562949953421231, 562949953421201, 562949953421189, @@ -1053,7 +1054,7 @@ const PRIMES49: &'static [u64] = &[ 562949953420297, ]; -const PRIMES50: &'static [u64] = &[ +const PRIMES50: &[u64] = &[ 1125899906842597, 1125899906842589, 1125899906842573, diff --git a/tests/by-util/test_head.rs b/tests/by-util/test_head.rs index b2a3cf0cb..cf7c9c2ee 100755 --- a/tests/by-util/test_head.rs +++ b/tests/by-util/test_head.rs @@ -1,6 +1,6 @@ use crate::common::util::*; -static INPUT: &'static str = "lorem_ipsum.txt"; +static INPUT: &str = "lorem_ipsum.txt"; #[test] fn test_stdin_default() { diff --git a/tests/by-util/test_install.rs b/tests/by-util/test_install.rs index fb79454c1..6da357170 100644 --- a/tests/by-util/test_install.rs +++ b/tests/by-util/test_install.rs @@ -116,11 +116,11 @@ fn test_install_ancestors_mode_directories() { assert!(at.dir_exists(ancestor2)); assert!(at.dir_exists(target_dir)); - assert_ne!(0o40700 as u32, at.metadata(ancestor1).permissions().mode()); - assert_ne!(0o40700 as u32, at.metadata(ancestor2).permissions().mode()); + assert_ne!(0o40_700_u32, at.metadata(ancestor1).permissions().mode()); + assert_ne!(0o40_700_u32, at.metadata(ancestor2).permissions().mode()); // Expected mode only on the target_dir. - assert_eq!(0o40700 as u32, at.metadata(target_dir).permissions().mode()); + assert_eq!(0o40_700_u32, at.metadata(target_dir).permissions().mode()); } #[test] @@ -184,7 +184,7 @@ fn test_install_mode_numeric() { assert!(at.file_exists(file)); assert!(at.file_exists(dest_file)); let permissions = at.metadata(dest_file).permissions(); - assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions)); + assert_eq!(0o100_333_u32, PermissionsExt::mode(&permissions)); let mode_arg = "-m 0333"; at.mkdir(dir2); @@ -195,7 +195,7 @@ fn test_install_mode_numeric() { assert!(at.file_exists(file)); assert!(at.file_exists(dest_file)); let permissions = at.metadata(dest_file).permissions(); - assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions)); + assert_eq!(0o100_333_u32, PermissionsExt::mode(&permissions)); } #[test] @@ -213,7 +213,7 @@ fn test_install_mode_symbolic() { assert!(at.file_exists(file)); assert!(at.file_exists(dest_file)); let permissions = at.metadata(dest_file).permissions(); - assert_eq!(0o100003 as u32, PermissionsExt::mode(&permissions)); + assert_eq!(0o100_003_u32, PermissionsExt::mode(&permissions)); } #[test] @@ -251,7 +251,7 @@ fn test_install_mode_directories() { assert!(at.dir_exists(component)); let permissions = at.metadata(component).permissions(); - assert_eq!(0o040333 as u32, PermissionsExt::mode(&permissions)); + assert_eq!(0o040_333_u32, PermissionsExt::mode(&permissions)); } #[test] diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 01c5ab5c4..d884948e6 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -51,6 +51,7 @@ fn test_ls_a() { .unwrap(), ); + #[allow(clippy::trivial_regex)] let re_pwd = Regex::new(r"^\.\n").unwrap(); // Using the present working directory @@ -124,7 +125,7 @@ fn test_ls_width() { for option in &["-w 100", "-w=100", "--width=100", "--width 100"] { scene .ucmd() - .args(&option.split(" ").collect::>()) + .args(&option.split(' ').collect::>()) .succeeds() .stdout_only("test-width-1 test-width-2 test-width-3 test-width-4\n"); } @@ -132,7 +133,7 @@ fn test_ls_width() { for option in &["-w 50", "-w=50", "--width=50", "--width 50"] { scene .ucmd() - .args(&option.split(" ").collect::>()) + .args(&option.split(' ').collect::>()) .succeeds() .stdout_only("test-width-1 test-width-3\ntest-width-2 test-width-4\n"); } @@ -149,7 +150,7 @@ fn test_ls_width() { ] { scene .ucmd() - .args(&option.split(" ").collect::>()) + .args(&option.split(' ').collect::>()) .succeeds() .stdout_only("test-width-1\ntest-width-2\ntest-width-3\ntest-width-4\n"); } @@ -163,7 +164,7 @@ fn test_ls_width() { for option in &["-w 1a", "-w=1a", "--width=1a", "--width 1a"] { scene .ucmd() - .args(&option.split(" ").collect::>()) + .args(&option.split(' ').collect::>()) .fails() .stderr_only("ls: invalid line width: ‘1a’"); } @@ -417,7 +418,7 @@ fn test_ls_long_formats() { ] { let result = scene .ucmd() - .args(&arg.split(" ").collect::>()) + .args(&arg.split(' ').collect::>()) .arg("test-long-formats") .succeeds(); assert!(re_two.is_match(result.stdout_str())); @@ -427,7 +428,7 @@ fn test_ls_long_formats() { let result = scene .ucmd() .arg("-n") - .args(&arg.split(" ").collect::>()) + .args(&arg.split(' ').collect::>()) .arg("test-long-formats") .succeeds(); assert!(re_two_num.is_match(result.stdout_str())); @@ -446,7 +447,7 @@ fn test_ls_long_formats() { ] { let result = scene .ucmd() - .args(&arg.split(" ").collect::>()) + .args(&arg.split(' ').collect::>()) .arg("test-long-formats") .succeeds(); assert!(re_one.is_match(result.stdout_str())); @@ -456,7 +457,7 @@ fn test_ls_long_formats() { let result = scene .ucmd() .arg("-n") - .args(&arg.split(" ").collect::>()) + .args(&arg.split(' ').collect::>()) .arg("test-long-formats") .succeeds(); assert!(re_one_num.is_match(result.stdout_str())); @@ -478,7 +479,7 @@ fn test_ls_long_formats() { ] { let result = scene .ucmd() - .args(&arg.split(" ").collect::>()) + .args(&arg.split(' ').collect::>()) .arg("test-long-formats") .succeeds(); assert!(re_zero.is_match(result.stdout_str())); @@ -488,7 +489,7 @@ fn test_ls_long_formats() { let result = scene .ucmd() .arg("-n") - .args(&arg.split(" ").collect::>()) + .args(&arg.split(' ').collect::>()) .arg("test-long-formats") .succeeds(); assert!(re_zero.is_match(result.stdout_str())); @@ -1063,7 +1064,7 @@ fn test_ls_indicator_style() { for opt in options { scene .ucmd() - .arg(format!("{}", opt)) + .arg(opt.to_string()) .succeeds() .stdout_contains(&"/"); } @@ -1085,7 +1086,10 @@ fn test_ls_indicator_style() { { use self::unix_socket::UnixListener; - let dir = tempfile::Builder::new().prefix("unix_socket").tempdir().expect("failed to create dir"); + let dir = tempfile::Builder::new() + .prefix("unix_socket") + .tempdir() + .expect("failed to create dir"); let socket_path = dir.path().join("sock"); let _listener = UnixListener::bind(&socket_path).expect("failed to create socket"); diff --git a/tests/by-util/test_mkdir.rs b/tests/by-util/test_mkdir.rs index ef3226c41..54a6fe3c8 100644 --- a/tests/by-util/test_mkdir.rs +++ b/tests/by-util/test_mkdir.rs @@ -1,12 +1,12 @@ use crate::common::util::*; -static TEST_DIR1: &'static str = "mkdir_test1"; -static TEST_DIR2: &'static str = "mkdir_test2"; -static TEST_DIR3: &'static str = "mkdir_test3"; -static TEST_DIR4: &'static str = "mkdir_test4/mkdir_test4_1"; -static TEST_DIR5: &'static str = "mkdir_test5/mkdir_test5_1"; -static TEST_DIR6: &'static str = "mkdir_test6"; -static TEST_FILE7: &'static str = "mkdir_test7"; +static TEST_DIR1: &str = "mkdir_test1"; +static TEST_DIR2: &str = "mkdir_test2"; +static TEST_DIR3: &str = "mkdir_test3"; +static TEST_DIR4: &str = "mkdir_test4/mkdir_test4_1"; +static TEST_DIR5: &str = "mkdir_test5/mkdir_test5_1"; +static TEST_DIR6: &str = "mkdir_test6"; +static TEST_FILE7: &str = "mkdir_test7"; #[test] fn test_mkdir_mkdir() { diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index 617f0fd06..d0737764f 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -3,19 +3,19 @@ use crate::common::util::*; use std::path::PathBuf; use tempfile::tempdir; -static TEST_TEMPLATE1: &'static str = "tempXXXXXX"; -static TEST_TEMPLATE2: &'static str = "temp"; -static TEST_TEMPLATE3: &'static str = "tempX"; -static TEST_TEMPLATE4: &'static str = "tempXX"; -static TEST_TEMPLATE5: &'static str = "tempXXX"; -static TEST_TEMPLATE6: &'static str = "tempXXXlate"; -static TEST_TEMPLATE7: &'static str = "XXXtemplate"; +static TEST_TEMPLATE1: &str = "tempXXXXXX"; +static TEST_TEMPLATE2: &str = "temp"; +static TEST_TEMPLATE3: &str = "tempX"; +static TEST_TEMPLATE4: &str = "tempXX"; +static TEST_TEMPLATE5: &str = "tempXXX"; +static TEST_TEMPLATE6: &str = "tempXXXlate"; +static TEST_TEMPLATE7: &str = "XXXtemplate"; #[cfg(unix)] -static TEST_TEMPLATE8: &'static str = "tempXXXl/ate"; +static TEST_TEMPLATE8: &str = "tempXXXl/ate"; #[cfg(windows)] -static TEST_TEMPLATE8: &'static str = "tempXXXl\\ate"; +static TEST_TEMPLATE8: &str = "tempXXXl\\ate"; -const TMPDIR: &'static str = "TMPDIR"; +const TMPDIR: &str = "TMPDIR"; #[test] fn test_mktemp_mktemp() { diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index e0bdd9ef3..beb8f61b9 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -82,7 +82,7 @@ fn test_mv_strip_slashes() { let dir = "test_mv_strip_slashes_dir"; let file = "test_mv_strip_slashes_file"; let mut source = file.to_owned(); - source.push_str("/"); + source.push('/'); at.mkdir(dir); at.touch(file); diff --git a/tests/by-util/test_od.rs b/tests/by-util/test_od.rs index b49e6f0ca..fa947aa6e 100644 --- a/tests/by-util/test_od.rs +++ b/tests/by-util/test_od.rs @@ -9,7 +9,7 @@ use std::io::Write; use std::path::Path; // octal dump of 'abcdefghijklmnopqrstuvwxyz\n' -static ALPHA_OUT: &'static str = " +static ALPHA_OUT: &str = " 0000000 061141 062143 063145 064147 065151 066153 067155 070157 0000020 071161 072163 073165 074167 075171 000012 0000033 @@ -563,7 +563,7 @@ fn test_dec_offset() { #[test] fn test_no_offset() { let input = [0u8; 31]; - const LINE: &'static str = " 00000000 00000000 00000000 00000000\n"; + const LINE: &str = " 00000000 00000000 00000000 00000000\n"; let expected_output = [LINE, LINE, LINE, LINE].join(""); new_ucmd!() diff --git a/tests/by-util/test_paste.rs b/tests/by-util/test_paste.rs index 4604c5cf5..1afe84be8 100644 --- a/tests/by-util/test_paste.rs +++ b/tests/by-util/test_paste.rs @@ -7,7 +7,7 @@ struct TestData<'b> { out: &'b str, } -static EXAMPLE_DATA: &'static [TestData<'static>] = &[ +static EXAMPLE_DATA: &[TestData] = &[ // Ensure that paste properly handles files lacking a final newline. TestData { name: "no-nl-1", @@ -64,8 +64,8 @@ static EXAMPLE_DATA: &'static [TestData<'static>] = &[ #[test] fn test_combine_pairs_of_lines() { - for s in vec!["-s", "--serial"] { - for d in vec!["-d", "--delimiters"] { + for &s in &["-s", "--serial"] { + for &d in &["-d", "--delimiters"] { new_ucmd!() .args(&[s, d, "\t\n", "html_colors.txt"]) .run() @@ -76,7 +76,7 @@ fn test_combine_pairs_of_lines() { #[test] fn test_multi_stdin() { - for d in vec!["-d", "--delimiters"] { + for &d in &["-d", "--delimiters"] { new_ucmd!() .args(&[d, "\t\n", "-", "-"]) .pipe_in_fixture("html_colors.txt") diff --git a/tests/by-util/test_readlink.rs b/tests/by-util/test_readlink.rs index cae5eafee..51aebbed2 100644 --- a/tests/by-util/test_readlink.rs +++ b/tests/by-util/test_readlink.rs @@ -1,6 +1,6 @@ use crate::common::util::*; -static GIBBERISH: &'static str = "supercalifragilisticexpialidocious"; +static GIBBERISH: &str = "supercalifragilisticexpialidocious"; #[test] fn test_canonicalize() { diff --git a/tests/by-util/test_relpath.rs b/tests/by-util/test_relpath.rs index 70d9f2a5d..b9c07fb12 100644 --- a/tests/by-util/test_relpath.rs +++ b/tests/by-util/test_relpath.rs @@ -61,6 +61,7 @@ const TESTS: [TestCase; 10] = [ }, ]; +#[allow(clippy::needless_lifetimes)] fn convert_path<'a>(path: &'a str) -> Cow<'a, str> { #[cfg(windows)] return path.replace("/", "\\").into(); diff --git a/tests/by-util/test_shuf.rs b/tests/by-util/test_shuf.rs index f925f8357..106d80a39 100644 --- a/tests/by-util/test_shuf.rs +++ b/tests/by-util/test_shuf.rs @@ -14,11 +14,11 @@ fn test_output_is_random_permutation() { let mut result_seq: Vec = result .stdout_str() - .split("\n") + .split('\n') .filter(|x| !x.is_empty()) .map(|x| x.parse().unwrap()) .collect(); - result_seq.sort(); + result_seq.sort_unstable(); assert_ne!(result.stdout_str(), input, "Output is not randomised"); assert_eq!(result_seq, input_seq, "Output is not a permutation"); } @@ -31,11 +31,11 @@ fn test_zero_termination() { let mut result_seq: Vec = result .stdout_str() - .split("\0") + .split('\0') .filter(|x| !x.is_empty()) .map(|x| x.parse().unwrap()) .collect(); - result_seq.sort(); + result_seq.sort_unstable(); assert_eq!(result_seq, input_seq, "Output is not a permutation"); } @@ -55,11 +55,11 @@ fn test_echo() { let mut result_seq: Vec = result .stdout_str() - .split("\n") + .split('\n') .filter(|x| !x.is_empty()) .map(|x| x.parse().unwrap()) .collect(); - result_seq.sort(); + result_seq.sort_unstable(); assert_eq!(result_seq, input_seq, "Output is not a permutation"); } @@ -81,11 +81,11 @@ fn test_head_count() { let mut result_seq: Vec = result .stdout_str() - .split("\n") + .split('\n') .filter(|x| !x.is_empty()) .map(|x| x.parse().unwrap()) .collect(); - result_seq.sort(); + result_seq.sort_unstable(); assert_eq!(result_seq.len(), repeat_limit, "Output is not limited"); assert!( result_seq.iter().all(|x| input_seq.contains(x)), @@ -113,7 +113,7 @@ fn test_repeat() { let result_seq: Vec = result .stdout_str() - .split("\n") + .split('\n') .filter(|x| !x.is_empty()) .map(|x| x.parse().unwrap()) .collect(); @@ -141,11 +141,11 @@ fn test_file_input() { let mut result_seq: Vec = result .stdout_str() - .split("\n") + .split('\n') .filter(|x| !x.is_empty()) .map(|x| x.parse().unwrap()) .collect(); - result_seq.sort(); + result_seq.sort_unstable(); assert_eq!(result_seq, expected_seq, "Output is not a permutation"); } diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index 3c0af259f..6a2350749 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -288,7 +288,7 @@ fn test_dictionary_order() { #[test] fn test_dictionary_order2() { - for non_dictionary_order2_param in vec!["-d"] { + for non_dictionary_order2_param in &["-d"] { new_ucmd!() .pipe_in("a👦🏻aa b\naaaa b") .arg(non_dictionary_order2_param) @@ -299,7 +299,7 @@ fn test_dictionary_order2() { #[test] fn test_non_printing_chars() { - for non_printing_chars_param in vec!["-i"] { + for non_printing_chars_param in &["-i"] { new_ucmd!() .pipe_in("a👦🏻aa\naaaa") .arg(non_printing_chars_param) @@ -361,7 +361,7 @@ fn test_mixed_floats_ints_chars_numeric_stable() { #[test] fn test_numeric_floats_and_ints2() { - for numeric_sort_param in vec!["-n", "--numeric-sort"] { + for numeric_sort_param in &["-n", "--numeric-sort"] { let input = "1.444\n8.013\n1\n-8\n1.04\n-1"; new_ucmd!() .arg(numeric_sort_param) @@ -373,7 +373,7 @@ fn test_numeric_floats_and_ints2() { #[test] fn test_numeric_floats2() { - for numeric_sort_param in vec!["-n", "--numeric-sort"] { + for numeric_sort_param in &["-n", "--numeric-sort"] { let input = "1.444\n8.013\n1.58590\n-8.90880\n1.040000000\n-.05"; new_ucmd!() .arg(numeric_sort_param) @@ -426,7 +426,7 @@ fn test_default_unsorted_ints2() { #[test] fn test_numeric_unique_ints2() { - for numeric_unique_sort_param in vec!["-nu"] { + for numeric_unique_sort_param in &["-nu"] { let input = "9\n9\n8\n1\n"; new_ucmd!() .arg(numeric_unique_sort_param) diff --git a/tests/by-util/test_split.rs b/tests/by-util/test_split.rs index d83de4323..1ff8bd8f2 100644 --- a/tests/by-util/test_split.rs +++ b/tests/by-util/test_split.rs @@ -98,7 +98,7 @@ impl RandomFile { let to_write = std::cmp::min(remaining_size, buffer.len()); let buf = &mut buffer[..to_write]; rng.fill(buf); - writer.write(buf).unwrap(); + writer.write_all(buf).unwrap(); remaining_size -= to_write; } @@ -179,6 +179,7 @@ fn test_split_bytes_prime_part_size() { let mut fns = glob.collect(); // glob.collect() is not guaranteed to return in sorted order, so we sort. fns.sort(); + #[allow(clippy::needless_range_loop)] for i in 0..5 { assert_eq!(glob.directory.metadata(&fns[i]).len(), 1753); } @@ -246,9 +247,9 @@ fn test_filter() { assert!( glob.collate().iter().find(|&&c| { // is not i - c != ('i' as u8) + c != (b'i') // is not newline - && c != ('\n' as u8) + && c != (b'\n') }) == None ); } @@ -271,7 +272,7 @@ fn test_filter_with_env_var_set() { let glob = Glob::new(&at, ".", r"x[[:alpha:]][[:alpha:]]$"); assert_eq!(glob.collate(), at.read_bytes(name)); - assert!(env::var("FILE").unwrap_or("var was unset".to_owned()) == env_var_value); + assert!(env::var("FILE").unwrap_or_else(|_| "var was unset".to_owned()) == env_var_value); } #[test] diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index 44bce9cd8..6935cc7f9 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -97,13 +97,13 @@ fn test_invalid_option() { } #[cfg(any(target_os = "linux", target_vendor = "apple"))] -const NORMAL_FMTSTR: &'static str = +const NORMAL_FMTSTR: &str = "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s %u %U %x %X %y %Y %z %Z"; // avoid "%w %W" (birth/creation) due to `stat` limitations and linux kernel & rust version capability variations #[cfg(any(target_os = "linux"))] -const DEV_FMTSTR: &'static str = +const DEV_FMTSTR: &str = "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (%t/%T) %u %U %w %W %x %X %y %Y %z %Z"; #[cfg(target_os = "linux")] -const FS_FMTSTR: &'static str = "%b %c %i %l %n %s %S %t %T"; // avoid "%a %d %f" which can cause test failure due to race conditions +const FS_FMTSTR: &str = "%b %c %i %l %n %s %S %t %T"; // avoid "%a %d %f" which can cause test failure due to race conditions #[test] #[cfg(target_os = "linux")] @@ -140,7 +140,7 @@ fn test_terse_normal_format() { assert!(!v_expect.is_empty()); // uu_stat does not support selinux - if v_actual.len() == v_expect.len() - 1 && v_expect[v_expect.len() - 1].contains(":") { + if v_actual.len() == v_expect.len() - 1 && v_expect[v_expect.len() - 1].contains(':') { // assume last element contains: `SELinux security context string` v_expect.pop(); } @@ -222,7 +222,7 @@ fn test_symlinks() { let mut tested: bool = false; // arbitrarily chosen symlinks with hope that the CI environment provides at least one of them - for file in vec![ + for file in &[ "/bin/sh", "/bin/sudoedit", "/usr/bin/ex", diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index f3c9a7b11..737d0cabf 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -5,9 +5,9 @@ use crate::common::util::*; use std::char::from_digit; use std::io::Write; -static FOOBAR_TXT: &'static str = "foobar.txt"; -static FOOBAR_2_TXT: &'static str = "foobar2.txt"; -static FOOBAR_WITH_NULL_TXT: &'static str = "foobar_with_null.txt"; +static FOOBAR_TXT: &str = "foobar.txt"; +static FOOBAR_2_TXT: &str = "foobar2.txt"; +static FOOBAR_WITH_NULL_TXT: &str = "foobar_with_null.txt"; #[test] fn test_stdin_default() { @@ -153,8 +153,8 @@ fn test_follow_with_pid() { #[test] fn test_single_big_args() { - const FILE: &'static str = "single_big_args.txt"; - const EXPECTED_FILE: &'static str = "single_big_args_expected.txt"; + const FILE: &str = "single_big_args.txt"; + const EXPECTED_FILE: &str = "single_big_args_expected.txt"; const LINES: usize = 1_000_000; const N_ARG: usize = 100_000; @@ -162,13 +162,13 @@ fn test_single_big_args() { let mut big_input = at.make_file(FILE); for i in 0..LINES { - write!(&mut big_input, "Line {}\n", i).expect("Could not write to FILE"); + writeln!(&mut big_input, "Line {}", i).expect("Could not write to FILE"); } big_input.flush().expect("Could not flush FILE"); let mut big_expected = at.make_file(EXPECTED_FILE); for i in (LINES - N_ARG)..LINES { - write!(&mut big_expected, "Line {}\n", i).expect("Could not write to EXPECTED_FILE"); + writeln!(&mut big_expected, "Line {}", i).expect("Could not write to EXPECTED_FILE"); } big_expected.flush().expect("Could not flush EXPECTED_FILE"); @@ -201,8 +201,8 @@ fn test_bytes_stdin() { #[test] fn test_bytes_big() { - const FILE: &'static str = "test_bytes_big.txt"; - const EXPECTED_FILE: &'static str = "test_bytes_big_expected.txt"; + const FILE: &str = "test_bytes_big.txt"; + const EXPECTED_FILE: &str = "test_bytes_big_expected.txt"; const BYTES: usize = 1_000_000; const N_ARG: usize = 100_000; @@ -257,10 +257,10 @@ fn test_parse_size() { for &(c, exp) in &suffixes { let s = format!("2{}B", c); - assert_eq!(Ok(2 * (1000 as u64).pow(exp)), parse_size(&s)); + assert_eq!(Ok(2 * (1000_u64).pow(exp)), parse_size(&s)); let s = format!("2{}", c); - assert_eq!(Ok(2 * (1024 as u64).pow(exp)), parse_size(&s)); + assert_eq!(Ok(2 * (1024_u64).pow(exp)), parse_size(&s)); } // Sizes that are too big. @@ -273,8 +273,8 @@ fn test_parse_size() { #[test] fn test_lines_with_size_suffix() { - const FILE: &'static str = "test_lines_with_size_suffix.txt"; - const EXPECTED_FILE: &'static str = "test_lines_with_size_suffix_expected.txt"; + const FILE: &str = "test_lines_with_size_suffix.txt"; + const EXPECTED_FILE: &str = "test_lines_with_size_suffix_expected.txt"; const LINES: usize = 3_000; const N_ARG: usize = 2 * 1024; diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 40fbb8aa9..d4d2c058e 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -401,8 +401,8 @@ fn get_dstswitch_hour() -> Option { for _i in 0..(366 * 24) { if is_dst_switch_hour(ts) { let mut tm = time::at(ts); - tm.tm_hour = tm.tm_hour + 1; - let s = time::strftime("%Y%m%d%H%M", &tm).unwrap().to_string(); + tm.tm_hour += 1; + let s = time::strftime("%Y%m%d%H%M", &tm).unwrap(); return Some(s); } ts = ts + time::Duration::hours(1); @@ -415,10 +415,7 @@ fn test_touch_mtime_dst_fails() { let (_at, mut ucmd) = at_and_ucmd!(); let file = "test_touch_set_mtime_dst_fails"; - match get_dstswitch_hour() { - Some(s) => { - ucmd.args(&["-m", "-t", &s, file]).fails(); - } - None => (), + if let Some(s) = get_dstswitch_hour() { + ucmd.args(&["-m", "-t", &s, file]).fails(); } } diff --git a/tests/by-util/test_truncate.rs b/tests/by-util/test_truncate.rs index 120982e3c..34ba59094 100644 --- a/tests/by-util/test_truncate.rs +++ b/tests/by-util/test_truncate.rs @@ -1,8 +1,8 @@ use crate::common::util::*; use std::io::{Seek, SeekFrom, Write}; -static TFILE1: &'static str = "truncate_test_1"; -static TFILE2: &'static str = "truncate_test_2"; +static TFILE1: &str = "truncate_test_1"; +static TFILE2: &str = "truncate_test_2"; #[test] fn test_increase_file_size() { diff --git a/tests/by-util/test_uniq.rs b/tests/by-util/test_uniq.rs index 2645c38ca..c191ffcaf 100644 --- a/tests/by-util/test_uniq.rs +++ b/tests/by-util/test_uniq.rs @@ -1,10 +1,10 @@ use crate::common::util::*; -static INPUT: &'static str = "sorted.txt"; -static OUTPUT: &'static str = "sorted-output.txt"; -static SKIP_CHARS: &'static str = "skip-chars.txt"; -static SKIP_FIELDS: &'static str = "skip-fields.txt"; -static SORTED_ZERO_TERMINATED: &'static str = "sorted-zero-terminated.txt"; +static INPUT: &str = "sorted.txt"; +static OUTPUT: &str = "sorted-output.txt"; +static SKIP_CHARS: &str = "skip-chars.txt"; +static SKIP_FIELDS: &str = "skip-fields.txt"; +static SORTED_ZERO_TERMINATED: &str = "sorted-zero-terminated.txt"; #[test] fn test_stdin_default() { diff --git a/tests/by-util/test_who.rs b/tests/by-util/test_who.rs index 21b5eb93e..333b03f5b 100644 --- a/tests/by-util/test_who.rs +++ b/tests/by-util/test_who.rs @@ -3,7 +3,7 @@ use crate::common::util::*; #[cfg(any(target_vendor = "apple", target_os = "linux"))] #[test] fn test_count() { - for opt in vec!["-q", "--count"] { + for opt in &["-q", "--count"] { new_ucmd!() .arg(opt) .succeeds() @@ -14,7 +14,7 @@ fn test_count() { #[cfg(any(target_vendor = "apple", target_os = "linux"))] #[test] fn test_boot() { - for opt in vec!["-b", "--boot"] { + for opt in &["-b", "--boot"] { new_ucmd!() .arg(opt) .succeeds() @@ -25,7 +25,7 @@ fn test_boot() { #[cfg(any(target_vendor = "apple", target_os = "linux"))] #[test] fn test_heading() { - for opt in vec!["-H", "--heading"] { + for opt in &["-H", "--heading"] { // allow whitespace variation // * minor whitespace differences occur between platform built-in outputs; // specifically number of TABs between "TIME" and "COMMENT" may be variant @@ -42,7 +42,7 @@ fn test_heading() { #[cfg(any(target_vendor = "apple", target_os = "linux"))] #[test] fn test_short() { - for opt in vec!["-s", "--short"] { + for opt in &["-s", "--short"] { new_ucmd!() .arg(opt) .succeeds() @@ -53,7 +53,7 @@ fn test_short() { #[cfg(any(target_vendor = "apple", target_os = "linux"))] #[test] fn test_login() { - for opt in vec!["-l", "--login"] { + for opt in &["-l", "--login"] { new_ucmd!() .arg(opt) .succeeds() @@ -64,7 +64,7 @@ fn test_login() { #[cfg(any(target_vendor = "apple", target_os = "linux"))] #[test] fn test_m() { - for opt in vec!["-m"] { + for opt in &["-m"] { new_ucmd!() .arg(opt) .succeeds() @@ -75,7 +75,7 @@ fn test_m() { #[cfg(any(target_vendor = "apple", target_os = "linux"))] #[test] fn test_process() { - for opt in vec!["-p", "--process"] { + for opt in &["-p", "--process"] { new_ucmd!() .arg(opt) .succeeds() @@ -85,7 +85,7 @@ fn test_process() { #[test] fn test_runlevel() { - for opt in vec!["-r", "--runlevel"] { + for opt in &["-r", "--runlevel"] { #[cfg(any(target_vendor = "apple", target_os = "linux"))] new_ucmd!() .arg(opt) @@ -100,7 +100,7 @@ fn test_runlevel() { #[cfg(any(target_vendor = "apple", target_os = "linux"))] #[test] fn test_time() { - for opt in vec!["-t", "--time"] { + for opt in &["-t", "--time"] { new_ucmd!() .arg(opt) .succeeds() @@ -117,7 +117,7 @@ fn test_mesg() { // same as -T // --writable // same as -T - for opt in vec!["-T", "-w", "--mesg", "--message", "--writable"] { + for opt in &["-T", "-w", "--mesg", "--message", "--writable"] { new_ucmd!() .arg(opt) .succeeds() @@ -147,7 +147,7 @@ fn test_too_many_args() { #[cfg(any(target_vendor = "apple", target_os = "linux"))] #[test] fn test_users() { - for opt in vec!["-u", "--users"] { + for opt in &["-u", "--users"] { let actual = new_ucmd!().arg(opt).succeeds().stdout_move_str(); let expect = expected_result(&[opt]); println!("actual: {:?}", actual); @@ -172,18 +172,17 @@ fn test_users() { #[cfg(any(target_vendor = "apple", target_os = "linux"))] #[test] fn test_lookup() { - for opt in vec!["--lookup"] { - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); - } + let opt = "--lookup"; + new_ucmd!() + .arg(opt) + .succeeds() + .stdout_is(expected_result(&[opt])); } #[cfg(any(target_vendor = "apple", target_os = "linux"))] #[test] fn test_dead() { - for opt in vec!["-d", "--dead"] { + for opt in &["-d", "--dead"] { new_ucmd!() .arg(opt) .succeeds() @@ -222,7 +221,7 @@ fn test_all() { return; } - for opt in vec!["-a", "--all"] { + for opt in &["-a", "--all"] { new_ucmd!() .arg(opt) .succeeds() diff --git a/tests/common/util.rs b/tests/common/util.rs index 7580d7be8..9ce7f0537 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -1,7 +1,4 @@ #![allow(dead_code)] - -#[cfg(not(windows))] -use libc; use pretty_assertions::assert_eq; use std::env; #[cfg(not(windows))] @@ -39,7 +36,7 @@ static NO_STDIN_MEANINGLESS: &str = "Setting this flag has no effect if there is /// Test if the program is running under CI pub fn is_ci() -> bool { std::env::var("CI") - .unwrap_or(String::from("false")) + .unwrap_or_else(|_| String::from("false")) .eq_ignore_ascii_case("true") } @@ -464,7 +461,7 @@ impl AtPath { .append(true) .open(self.plus(name)) .unwrap(); - f.write(contents.as_bytes()) + f.write_all(contents.as_bytes()) .unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e)); } @@ -777,7 +774,7 @@ impl UCommand { if self.has_run { panic!("{}", ALREADY_RUN); } - self.comm_string.push_str(" "); + self.comm_string.push(' '); self.comm_string .push_str(arg.as_ref().to_str().unwrap_or_default()); self.raw.arg(arg.as_ref()); @@ -797,7 +794,7 @@ impl UCommand { .accept_any(); for s in strings { - self.comm_string.push_str(" "); + self.comm_string.push(' '); self.comm_string.push_str(&s); } @@ -853,9 +850,9 @@ impl UCommand { log_info("run", &self.comm_string); let mut child = self .raw - .stdin(self.stdin.take().unwrap_or_else(|| Stdio::piped())) - .stdout(self.stdout.take().unwrap_or_else(|| Stdio::piped())) - .stderr(self.stderr.take().unwrap_or_else(|| Stdio::piped())) + .stdin(self.stdin.take().unwrap_or_else(Stdio::piped)) + .stdout(self.stdout.take().unwrap_or_else(Stdio::piped)) + .stderr(self.stderr.take().unwrap_or_else(Stdio::piped)) .spawn() .unwrap(); @@ -929,10 +926,7 @@ pub fn read_size(child: &mut Child, size: usize) -> String { } pub fn vec_of_size(n: usize) -> Vec { - let mut result = Vec::new(); - for _ in 0..n { - result.push('a' as u8); - } + let result = vec![b'a'; n]; assert_eq!(result.len(), n); result } From e4aa8ee1593e24d5fc064e0cd2c83a000f3ec0d4 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sat, 29 May 2021 01:51:00 +0200 Subject: [PATCH 21/39] users: fix long_help text and clippy warning --- src/uu/users/src/users.rs | 21 +++++++++++++-------- tests/by-util/test_users.rs | 28 ++++++++++++---------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/uu/users/src/users.rs b/src/uu/users/src/users.rs index 4bb628441..99e06c1af 100644 --- a/src/uu/users/src/users.rs +++ b/src/uu/users/src/users.rs @@ -6,19 +6,14 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. -/* last synced with: whoami (GNU coreutils) 8.22 */ -// Allow dead code here in order to keep all fields, constants here, for consistency. -#![allow(dead_code)] - #[macro_use] extern crate uucore; -use uucore::utmpx::*; - use clap::{App, Arg}; +use uucore::utmpx::{self, Utmpx}; -static ABOUT: &str = "Display who is currently logged in, according to FILE."; static VERSION: &str = env!("CARGO_PKG_VERSION"); +static ABOUT: &str = "Print the user names of users currently logged in to the current host"; static ARG_FILES: &str = "files"; @@ -26,13 +21,23 @@ fn get_usage() -> String { format!("{0} [FILE]", executable!()) } +fn get_long_usage() -> String { + format!( + "Output who is currently logged in according to FILE. +If FILE is not specified, use {}. /var/log/wtmp as FILE is common.", + utmpx::DEFAULT_FILE + ) +} + pub fn uumain(args: impl uucore::Args) -> i32 { let usage = get_usage(); + let after_help = get_long_usage(); let matches = App::new(executable!()) .version(VERSION) .about(ABOUT) .usage(&usage[..]) + .after_help(&after_help[..]) .arg(Arg::with_name(ARG_FILES).takes_value(true).max_values(1)) .get_matches_from(args); @@ -44,7 +49,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let filename = if !files.is_empty() { files[0].as_ref() } else { - DEFAULT_FILE + utmpx::DEFAULT_FILE }; let mut users = Utmpx::iter_all_records() diff --git a/tests/by-util/test_users.rs b/tests/by-util/test_users.rs index 3c5789820..89c3fdd0f 100644 --- a/tests/by-util/test_users.rs +++ b/tests/by-util/test_users.rs @@ -1,27 +1,23 @@ use crate::common::util::*; -use std::env; #[test] fn test_users_noarg() { new_ucmd!().succeeds(); } + #[test] +#[cfg(any(target_vendor = "apple", target_os = "linux"))] fn test_users_check_name() { - let result = TestScenario::new(util_name!()).ucmd_keepenv().succeeds(); + #[cfg(target_os = "linux")] + let util_name = util_name!(); + #[cfg(target_vendor = "apple")] + let util_name = format!("g{}", util_name!()); - // Expectation: USER is often set - let key = "USER"; + let expected = TestScenario::new(&util_name) + .cmd_keepenv(util_name) + .env("LANGUAGE", "C") + .succeeds() + .stdout_move_str(); - match env::var(key) { - Err(e) => println!("Key {} isn't set. Found {}", &key, e), - Ok(username) => - // Check if "users" contains the name of the user - { - println!("username found {}", &username); - // println!("result.stdout {}", &result.stdout); - if !result.stdout_str().is_empty() { - result.stdout_contains(&username); - } - } - } + new_ucmd!().succeeds().stdout_is(&expected); } From 17b0939deed110944ff36239d5cb207cc33fe160 Mon Sep 17 00:00:00 2001 From: Gilad Naaman Date: Fri, 28 May 2021 18:28:00 +0300 Subject: [PATCH 22/39] Moved factor to use clap Issue: https://github.com/uutils/coreutils/issues/2121 --- Cargo.lock | 1 + src/uu/factor/Cargo.toml | 1 + src/uu/factor/src/cli.rs | 36 ++++++++++++++++++++---------------- tests/by-util/test_factor.rs | 12 ++++++++++++ 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f0b4efcd..6d2a47c84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1821,6 +1821,7 @@ dependencies = [ name = "uu_factor" version = "0.0.6" dependencies = [ + "clap", "coz", "num-traits", "paste", diff --git a/src/uu/factor/Cargo.toml b/src/uu/factor/Cargo.toml index eb34519f1..eb977760f 100644 --- a/src/uu/factor/Cargo.toml +++ b/src/uu/factor/Cargo.toml @@ -21,6 +21,7 @@ rand = { version = "0.7", features = ["small_rng"] } smallvec = { version = "0.6.14, < 1.0" } uucore = { version = ">=0.0.8", package = "uucore", path = "../../uucore" } uucore_procs = { version = ">=0.0.5", package = "uucore_procs", path = "../../uucore_procs" } +clap = "2.33" [dev-dependencies] paste = "0.1.18" diff --git a/src/uu/factor/src/cli.rs b/src/uu/factor/src/cli.rs index ee4c8a4c4..69a368479 100644 --- a/src/uu/factor/src/cli.rs +++ b/src/uu/factor/src/cli.rs @@ -13,18 +13,21 @@ use std::error::Error; use std::io::{self, stdin, stdout, BufRead, Write}; mod factor; +use clap::{App, Arg}; pub use factor::*; -use uucore::InvalidEncodingHandling; mod miller_rabin; pub mod numeric; mod rho; pub mod table; -static SYNTAX: &str = "[OPTION] [NUMBER]..."; -static SUMMARY: &str = "Print the prime factors of the given number(s). - If none are specified, read from standard input."; -static LONG_HELP: &str = ""; +static VERSION: &str = env!("CARGO_PKG_VERSION"); +static SUMMARY: &str = "Print the prime factors of the given NUMBER(s). +If none are specified, read from standard input."; + +mod options { + pub static NUMBER: &str = "NUMBER"; +} fn print_factors_str(num_str: &str, w: &mut impl io::Write) -> Result<(), Box> { num_str @@ -34,14 +37,21 @@ fn print_factors_str(num_str: &str, w: &mut impl io::Write) -> Result<(), Box i32 { - let matches = app!(SYNTAX, SUMMARY, LONG_HELP).parse( - args.collect_str(InvalidEncodingHandling::Ignore) - .accept_any(), - ); + let matches = App::new(executable!()) + .version(VERSION) + .about(SUMMARY) + .arg(Arg::with_name(options::NUMBER).multiple(true)) + .get_matches_from(args); let stdout = stdout(); let mut w = io::BufWriter::new(stdout.lock()); - if matches.free.is_empty() { + if let Some(values) = matches.values_of(options::NUMBER) { + for number in values { + if let Err(e) = print_factors_str(number, &mut w) { + show_warning!("{}: {}", number, e); + } + } + } else { let stdin = stdin(); for line in stdin.lock().lines() { @@ -51,12 +61,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 { } } } - } else { - for number in &matches.free { - if let Err(e) = print_factors_str(number, &mut w) { - show_warning!("{}: {}", number, e); - } - } } if let Err(e) = w.flush() { diff --git a/tests/by-util/test_factor.rs b/tests/by-util/test_factor.rs index 963b82ed8..917d19a49 100644 --- a/tests/by-util/test_factor.rs +++ b/tests/by-util/test_factor.rs @@ -40,6 +40,18 @@ fn test_first_100000_integers() { assert_eq!(hash_check, "4ed2d8403934fa1c76fe4b84c5d4b8850299c359"); } +#[test] +fn test_cli_args() { + // Make sure that factor works with CLI arguments as well. + new_ucmd!().args(&["3"]).succeeds().stdout_contains("3: 3"); + + new_ucmd!() + .args(&["3", "6"]) + .succeeds() + .stdout_contains("3: 3") + .stdout_contains("6: 2 3"); +} + #[test] fn test_random() { use conv::prelude::*; From 4e73b919e9ff96472433d0380c53383e892b6d80 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Fri, 21 May 2021 18:20:05 -0400 Subject: [PATCH 23/39] truncate: add test for -r and -s options together Add a test for when the reference file is not found and both `-r` and `-s` options are given on the command-line. --- tests/by-util/test_truncate.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/by-util/test_truncate.rs b/tests/by-util/test_truncate.rs index 34ba59094..a28ce9451 100644 --- a/tests/by-util/test_truncate.rs +++ b/tests/by-util/test_truncate.rs @@ -262,3 +262,11 @@ fn test_reference_file_not_found() { .fails() .stderr_contains("cannot stat 'a': No such file or directory"); } + +#[test] +fn test_reference_with_size_file_not_found() { + new_ucmd!() + .args(&["-r", "a", "-s", "+1", "b"]) + .fails() + .stderr_contains("cannot stat 'a': No such file or directory"); +} From b898e54d7a35c5978ca707b903d04da13060471f Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Fri, 21 May 2021 18:23:50 -0400 Subject: [PATCH 24/39] truncate: remove read permissions from OpenOptions Remove "read" permissions from the `OpenOptions` when opening a new file just to truncate it. We will never read from the file, only write to it. (Specifically, we will only call `File::set_len()`.) --- src/uu/truncate/src/truncate.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/uu/truncate/src/truncate.rs b/src/uu/truncate/src/truncate.rs index 03b18723c..086e14858 100644 --- a/src/uu/truncate/src/truncate.rs +++ b/src/uu/truncate/src/truncate.rs @@ -189,12 +189,7 @@ fn truncate( }; for filename in &filenames { let path = Path::new(filename); - match OpenOptions::new() - .read(true) - .write(true) - .create(!no_create) - .open(path) - { + match OpenOptions::new().write(true).create(!no_create).open(path) { Ok(file) => { let fsize = match reference { Some(_) => refsize, From 005bc259da0cbd6128b9d803693096df49b79e78 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Fri, 21 May 2021 21:06:45 -0400 Subject: [PATCH 25/39] truncate: add parse_mode_and_size() helper func Add a helper function to contain the code for parsing the size and the modifier symbol, if any. This commit also changes the `TruncateMode` enum so that the parameter for each "mode" is stored along with the enumeration value. This is because the parameter has a different meaning in each mode. --- src/uu/truncate/src/truncate.rs | 136 ++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 51 deletions(-) diff --git a/src/uu/truncate/src/truncate.rs b/src/uu/truncate/src/truncate.rs index 086e14858..9df775300 100644 --- a/src/uu/truncate/src/truncate.rs +++ b/src/uu/truncate/src/truncate.rs @@ -15,16 +15,16 @@ use std::fs::{metadata, OpenOptions}; use std::io::ErrorKind; use std::path::Path; -#[derive(Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] enum TruncateMode { - Absolute, - Reference, - Extend, - Reduce, - AtMost, - AtLeast, - RoundDown, - RoundUp, + Reference(u64), + Absolute(u64), + Extend(u64), + Reduce(u64), + AtMost(u64), + AtLeast(u64), + RoundDown(u64), + RoundUp(u64), } static ABOUT: &str = "Shrink or extend the size of each file to the specified size."; @@ -133,46 +133,21 @@ fn truncate( size: Option, filenames: Vec, ) { - let (modsize, mode) = match size { - Some(size_string) => { - // Trim any whitespace. - let size_string = size_string.trim(); - - // Get the modifier character from the size string, if any. For - // example, if the argument is "+123", then the modifier is '+'. - let c = size_string.chars().next().unwrap(); - - let mode = match c { - '+' => TruncateMode::Extend, - '-' => TruncateMode::Reduce, - '<' => TruncateMode::AtMost, - '>' => TruncateMode::AtLeast, - '/' => TruncateMode::RoundDown, - '%' => TruncateMode::RoundUp, - _ => TruncateMode::Absolute, /* assume that the size is just a number */ - }; - - // If there was a modifier character, strip it. - let size_string = match mode { - TruncateMode::Absolute => size_string, - _ => &size_string[1..], - }; - let num_bytes = match parse_size(size_string) { - Ok(b) => b, - Err(_) => crash!(1, "Invalid number: ‘{}’", size_string), - }; - (num_bytes, mode) - } - None => (0, TruncateMode::Reference), + let mode = match size { + Some(size_string) => match parse_mode_and_size(&size_string) { + Ok(m) => m, + Err(_) => crash!(1, "Invalid number: ‘{}’", size_string), + }, + None => TruncateMode::Reference(0), }; let refsize = match reference { Some(ref rfilename) => { match mode { // Only Some modes work with a reference - TruncateMode::Reference => (), //No --size was given - TruncateMode::Extend => (), - TruncateMode::Reduce => (), + TruncateMode::Reference(_) => (), //No --size was given + TruncateMode::Extend(_) => (), + TruncateMode::Reduce(_) => (), _ => crash!(1, "you must specify a relative ‘--size’ with ‘--reference’"), }; match metadata(rfilename) { @@ -202,14 +177,14 @@ fn truncate( }, }; let tsize: u64 = match mode { - TruncateMode::Absolute => modsize, - TruncateMode::Reference => fsize, - TruncateMode::Extend => fsize + modsize, - TruncateMode::Reduce => fsize - modsize, - TruncateMode::AtMost => fsize.min(modsize), - TruncateMode::AtLeast => fsize.max(modsize), - TruncateMode::RoundDown => fsize - fsize % modsize, - TruncateMode::RoundUp => fsize + fsize % modsize, + TruncateMode::Absolute(modsize) => modsize, + TruncateMode::Reference(_) => fsize, + TruncateMode::Extend(modsize) => fsize + modsize, + TruncateMode::Reduce(modsize) => fsize - modsize, + TruncateMode::AtMost(modsize) => fsize.min(modsize), + TruncateMode::AtLeast(modsize) => fsize.max(modsize), + TruncateMode::RoundDown(modsize) => fsize - fsize % modsize, + TruncateMode::RoundUp(modsize) => fsize + fsize % modsize, }; match file.set_len(tsize) { Ok(_) => {} @@ -221,6 +196,52 @@ fn truncate( } } +/// Decide whether a character is one of the size modifiers, like '+' or '<'. +fn is_modifier(c: char) -> bool { + c == '+' || c == '-' || c == '<' || c == '>' || c == '/' || c == '%' +} + +/// Parse a size string with optional modifier symbol as its first character. +/// +/// A size string is as described in [`parse_size`]. The first character +/// of `size_string` might be a modifier symbol, like `'+'` or +/// `'<'`. The first element of the pair returned by this function +/// indicates which modifier symbol was present, or +/// [`TruncateMode::Absolute`] if none. +/// +/// # Panics +/// +/// If `size_string` is empty, or if no number could be parsed from the +/// given string (for example, if the string were `"abc"`). +/// +/// # Examples +/// +/// ```rust,ignore +/// assert_eq!(parse_mode_and_size("+123"), (TruncateMode::Extend, 123)); +/// ``` +fn parse_mode_and_size(size_string: &str) -> Result { + // Trim any whitespace. + let size_string = size_string.trim(); + + // Get the modifier character from the size string, if any. For + // example, if the argument is "+123", then the modifier is '+'. + let c = size_string.chars().next().unwrap(); + let size_string = if is_modifier(c) { + &size_string[1..] + } else { + size_string + }; + parse_size(size_string).map(match c { + '+' => TruncateMode::Extend, + '-' => TruncateMode::Reduce, + '<' => TruncateMode::AtMost, + '>' => TruncateMode::AtLeast, + '/' => TruncateMode::RoundDown, + '%' => TruncateMode::RoundUp, + _ => TruncateMode::Absolute, + }) +} + /// Parse a size string into a number of bytes. /// /// A size string comprises an integer and an optional unit. The unit @@ -280,7 +301,9 @@ fn parse_size(size: &str) -> Result { #[cfg(test)] mod tests { + use crate::parse_mode_and_size; use crate::parse_size; + use crate::TruncateMode; #[test] fn test_parse_size_zero() { @@ -306,4 +329,15 @@ mod tests { assert_eq!(parse_size("123M").unwrap(), 123 * 1024 * 1024); assert_eq!(parse_size("123MB").unwrap(), 123 * 1000 * 1000); } + + #[test] + fn test_parse_mode_and_size() { + assert_eq!(parse_mode_and_size("10"), Ok(TruncateMode::Absolute(10))); + assert_eq!(parse_mode_and_size("+10"), Ok(TruncateMode::Extend(10))); + assert_eq!(parse_mode_and_size("-10"), Ok(TruncateMode::Reduce(10))); + assert_eq!(parse_mode_and_size("<10"), Ok(TruncateMode::AtMost(10))); + assert_eq!(parse_mode_and_size(">10"), Ok(TruncateMode::AtLeast(10))); + assert_eq!(parse_mode_and_size("/10"), Ok(TruncateMode::RoundDown(10))); + assert_eq!(parse_mode_and_size("%10"), Ok(TruncateMode::RoundUp(10))); + } } From 5129114ddc9b7b29f5aac2e6d93b2dc44df60a6f Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Fri, 21 May 2021 21:09:33 -0400 Subject: [PATCH 26/39] truncate: create TruncateMode::to_size() method Create a method that computes the final target size in bytes for the file to truncate, given the reference file size and the parameter to the `TruncateMode`. --- src/uu/truncate/src/truncate.rs | 37 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/uu/truncate/src/truncate.rs b/src/uu/truncate/src/truncate.rs index 9df775300..c0f078458 100644 --- a/src/uu/truncate/src/truncate.rs +++ b/src/uu/truncate/src/truncate.rs @@ -27,6 +27,32 @@ enum TruncateMode { RoundUp(u64), } +impl TruncateMode { + /// Compute a target size in bytes for this truncate mode. + /// + /// `fsize` is the size of the reference file, in bytes. + /// + /// # Examples + /// + /// ```rust,ignore + /// let mode = TruncateMode::Extend(5); + /// let fsize = 10; + /// assert_eq!(mode.to_size(fsize), 15); + /// ``` + fn to_size(&self, fsize: u64) -> u64 { + match self { + TruncateMode::Absolute(modsize) => *modsize, + TruncateMode::Reference(_) => fsize, + TruncateMode::Extend(modsize) => fsize + modsize, + TruncateMode::Reduce(modsize) => fsize - modsize, + TruncateMode::AtMost(modsize) => fsize.min(*modsize), + TruncateMode::AtLeast(modsize) => fsize.max(*modsize), + TruncateMode::RoundDown(modsize) => fsize - fsize % modsize, + TruncateMode::RoundUp(modsize) => fsize + fsize % modsize, + } + } +} + static ABOUT: &str = "Shrink or extend the size of each file to the specified size."; static VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -176,16 +202,7 @@ fn truncate( } }, }; - let tsize: u64 = match mode { - TruncateMode::Absolute(modsize) => modsize, - TruncateMode::Reference(_) => fsize, - TruncateMode::Extend(modsize) => fsize + modsize, - TruncateMode::Reduce(modsize) => fsize - modsize, - TruncateMode::AtMost(modsize) => fsize.min(modsize), - TruncateMode::AtLeast(modsize) => fsize.max(modsize), - TruncateMode::RoundDown(modsize) => fsize - fsize % modsize, - TruncateMode::RoundUp(modsize) => fsize + fsize % modsize, - }; + let tsize = mode.to_size(fsize); match file.set_len(tsize) { Ok(_) => {} Err(f) => crash!(1, "{}", f.to_string()), From 0999b00ff9e78e93746605140c70bc022a43a374 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Fri, 21 May 2021 21:12:13 -0400 Subject: [PATCH 27/39] truncate: re-organize into one func for each mode Reorganize the code in `truncate.rs` into three distinct functions representing the three modes of operation of the `truncate` program. The three modes are - `truncate -r RFILE FILE`, which sets the length of `FILE` to match the length of `RFILE`, - `truncate -r RFILE -s NUM FILE`, which sets the length of `FILE` relative to the given `RFILE`, - `truncate -s NUM FILE`, which sets the length of `FILE` either absolutely or relative to its curent length. This organization of the code makes it more concise and easier to follow. --- src/uu/truncate/src/truncate.rs | 196 ++++++++++++++++++++++---------- 1 file changed, 139 insertions(+), 57 deletions(-) diff --git a/src/uu/truncate/src/truncate.rs b/src/uu/truncate/src/truncate.rs index c0f078458..3a6077b3c 100644 --- a/src/uu/truncate/src/truncate.rs +++ b/src/uu/truncate/src/truncate.rs @@ -17,7 +17,6 @@ use std::path::Path; #[derive(Debug, Eq, PartialEq)] enum TruncateMode { - Reference(u64), Absolute(u64), Extend(u64), Reduce(u64), @@ -42,7 +41,6 @@ impl TruncateMode { fn to_size(&self, fsize: u64) -> u64 { match self { TruncateMode::Absolute(modsize) => *modsize, - TruncateMode::Reference(_) => fsize, TruncateMode::Extend(modsize) => fsize + modsize, TruncateMode::Reduce(modsize) => fsize - modsize, TruncateMode::AtMost(modsize) => fsize.min(*modsize), @@ -142,74 +140,158 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let no_create = matches.is_present(options::NO_CREATE); let reference = matches.value_of(options::REFERENCE).map(String::from); let size = matches.value_of(options::SIZE).map(String::from); - if reference.is_none() && size.is_none() { - crash!(1, "you must specify either --reference or --size"); - } else { - truncate(no_create, io_blocks, reference, size, files); + if let Err(e) = truncate(no_create, io_blocks, reference, size, files) { + match e.kind() { + ErrorKind::NotFound => { + // TODO Improve error-handling so that the error + // returned by `truncate()` provides the necessary + // parameter for formatting the error message. + let reference = matches.value_of(options::REFERENCE).map(String::from); + crash!( + 1, + "cannot stat '{}': No such file or directory", + reference.unwrap() + ); + } + _ => crash!(1, "{}", e.to_string()), + } } } 0 } +/// Truncate the named file to the specified size. +/// +/// If `create` is true, then the file will be created if it does not +/// already exist. If `size` is larger than the number of bytes in the +/// file, then the file will be padded with zeros. If `size` is smaller +/// than the number of bytes in the file, then the file will be +/// truncated and any bytes beyond `size` will be lost. +/// +/// # Errors +/// +/// If the file could not be opened, or there was a problem setting the +/// size of the file. +fn file_truncate(filename: &str, create: bool, size: u64) -> std::io::Result<()> { + let path = Path::new(filename); + let f = OpenOptions::new().write(true).create(create).open(path)?; + f.set_len(size) +} + +/// Truncate files to a size relative to a given file. +/// +/// `rfilename` is the name of the reference file. +/// +/// `size_string` gives the size relative to the reference file to which +/// to set the target files. For example, "+3K" means "set each file to +/// be three kilobytes larger than the size of the reference file". +/// +/// If `create` is true, then each file will be created if it does not +/// already exist. +/// +/// # Errors +/// +/// If the any file could not be opened, or there was a problem setting +/// the size of at least one file. +fn truncate_reference_and_size( + rfilename: &str, + size_string: &str, + filenames: Vec, + create: bool, +) -> std::io::Result<()> { + let mode = match parse_mode_and_size(size_string) { + Ok(m) => match m { + TruncateMode::Absolute(_) => { + crash!(1, "you must specify a relative ‘--size’ with ‘--reference’") + } + _ => m, + }, + Err(_) => crash!(1, "Invalid number: ‘{}’", size_string), + }; + let fsize = metadata(rfilename)?.len(); + let tsize = mode.to_size(fsize); + for filename in &filenames { + file_truncate(filename, create, tsize)?; + } + Ok(()) +} + +/// Truncate files to match the size of a given reference file. +/// +/// `rfilename` is the name of the reference file. +/// +/// If `create` is true, then each file will be created if it does not +/// already exist. +/// +/// # Errors +/// +/// If the any file could not be opened, or there was a problem setting +/// the size of at least one file. +fn truncate_reference_file_only( + rfilename: &str, + filenames: Vec, + create: bool, +) -> std::io::Result<()> { + let tsize = metadata(rfilename)?.len(); + for filename in &filenames { + file_truncate(filename, create, tsize)?; + } + Ok(()) +} + +/// Truncate files to a specified size. +/// +/// `size_string` gives either an absolute size or a relative size. A +/// relative size adjusts the size of each file relative to its current +/// size. For example, "3K" means "set each file to be three kilobytes" +/// whereas "+3K" means "set each file to be three kilobytes larger than +/// its current size". +/// +/// If `create` is true, then each file will be created if it does not +/// already exist. +/// +/// # Errors +/// +/// If the any file could not be opened, or there was a problem setting +/// the size of at least one file. +fn truncate_size_only( + size_string: &str, + filenames: Vec, + create: bool, +) -> std::io::Result<()> { + let mode = match parse_mode_and_size(size_string) { + Ok(m) => m, + Err(_) => crash!(1, "Invalid number: ‘{}’", size_string), + }; + for filename in &filenames { + let fsize = metadata(filename).map(|m| m.len()).unwrap_or(0); + let tsize = mode.to_size(fsize); + file_truncate(filename, create, tsize)?; + } + Ok(()) +} + fn truncate( no_create: bool, _: bool, reference: Option, size: Option, filenames: Vec, -) { - let mode = match size { - Some(size_string) => match parse_mode_and_size(&size_string) { - Ok(m) => m, - Err(_) => crash!(1, "Invalid number: ‘{}’", size_string), - }, - None => TruncateMode::Reference(0), - }; - - let refsize = match reference { - Some(ref rfilename) => { - match mode { - // Only Some modes work with a reference - TruncateMode::Reference(_) => (), //No --size was given - TruncateMode::Extend(_) => (), - TruncateMode::Reduce(_) => (), - _ => crash!(1, "you must specify a relative ‘--size’ with ‘--reference’"), - }; - match metadata(rfilename) { - Ok(meta) => meta.len(), - Err(f) => match f.kind() { - ErrorKind::NotFound => { - crash!(1, "cannot stat '{}': No such file or directory", rfilename) - } - _ => crash!(1, "{}", f.to_string()), - }, - } - } - None => 0, - }; - for filename in &filenames { - let path = Path::new(filename); - match OpenOptions::new().write(true).create(!no_create).open(path) { - Ok(file) => { - let fsize = match reference { - Some(_) => refsize, - None => match metadata(filename) { - Ok(meta) => meta.len(), - Err(f) => { - show_warning!("{}", f.to_string()); - continue; - } - }, - }; - let tsize = mode.to_size(fsize); - match file.set_len(tsize) { - Ok(_) => {} - Err(f) => crash!(1, "{}", f.to_string()), - }; - } - Err(f) => crash!(1, "{}", f.to_string()), +) -> std::io::Result<()> { + let create = !no_create; + // There are four possibilities + // - reference file given and size given, + // - reference file given but no size given, + // - no reference file given but size given, + // - no reference file given and no size given, + match (reference, size) { + (Some(rfilename), Some(size_string)) => { + truncate_reference_and_size(&rfilename, &size_string, filenames, create) } + (Some(rfilename), None) => truncate_reference_file_only(&rfilename, filenames, create), + (None, Some(size_string)) => truncate_size_only(&size_string, filenames, create), + (None, None) => crash!(1, "you must specify either --reference or --size"), } } From 4058caa3e60fba539a62ea47faa065e17639cd0e Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Sat, 29 May 2021 21:28:58 +0200 Subject: [PATCH 28/39] maint: add spell checker to CICD --- .github/workflows/CICD.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 804720bea..de7a31938 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -614,3 +614,20 @@ jobs: flags: ${{ steps.vars.outputs.CODECOV_FLAGS }} name: codecov-umbrella fail_ci_if_error: false + spellcheck: + name: Spell Check + runs-on: ${{ matrix.job.os }} + strategy: + matrix: + job: + - { os: ubuntu-latest } + steps: + - uses: actions/checkout@v1 + - name: Install/setup prerequisites + shell: bash + run: | + sudo apt-get -y update ; sudo apt-get -y install npm ; sudo npm install cspell -g; + - name: Run `cspell` + shell: bash + run: | + cspell --config .vscode/cSpell.json --no-summary --no-progress $( git ls-files | grep "\.\(rs\|md\)" ) | sed "s/\(.*\):\(.*\):\(.*\) - \(.*\)/::warning file=\1,line=\2,col=\3::cspell: \4/" || true From d821719c67a6f3a6f7d67d4f1c04527451dd7bb1 Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Sat, 29 May 2021 23:25:23 +0200 Subject: [PATCH 29/39] expr: support arbitrary precision integers (#2271) * expr: support arbitrary precision integers Instead of i64s we now use BigInts for integer operations. This means that no result or input can be out of range. The representation of integer flags was changed from i64 to u8 to make their intention clearer. * expr: allow big numbers as arguments as well Also adds some tests * expr: use num-traits to check bigints for 0 and 1 * expr: remove obsolete refs match ergonomics made these avoidable. * formatting Co-authored-by: Sylvestre Ledru --- Cargo.lock | 13 ++++ src/uu/expr/Cargo.toml | 2 + src/uu/expr/src/syntax_tree.rs | 107 +++++++++++++++------------------ src/uu/expr/src/tokens.rs | 12 ++-- tests/by-util/test_expr.rs | 78 ++++++++++++++++++------ 5 files changed, 128 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6d2a47c84..997e1f458 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -859,6 +859,17 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "num-bigint" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -1812,6 +1823,8 @@ name = "uu_expr" version = "0.0.6" dependencies = [ "libc", + "num-bigint", + "num-traits", "onig", "uucore", "uucore_procs", diff --git a/src/uu/expr/Cargo.toml b/src/uu/expr/Cargo.toml index c535df7ce..ed992bf71 100644 --- a/src/uu/expr/Cargo.toml +++ b/src/uu/expr/Cargo.toml @@ -16,6 +16,8 @@ path = "src/expr.rs" [dependencies] libc = "0.2.42" +num-bigint = "0.4.0" +num-traits = "0.2.14" onig = "~4.3.2" uucore = { version=">=0.0.8", package="uucore", path="../../uucore" } uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" } diff --git a/src/uu/expr/src/syntax_tree.rs b/src/uu/expr/src/syntax_tree.rs index a75f4c742..b72d78729 100644 --- a/src/uu/expr/src/syntax_tree.rs +++ b/src/uu/expr/src/syntax_tree.rs @@ -12,6 +12,8 @@ // spell-checker:ignore (ToDO) binop binops ints paren prec +use num_bigint::BigInt; +use num_traits::{One, Zero}; use onig::{Regex, RegexOptions, Syntax}; use crate::tokens::Token; @@ -39,20 +41,17 @@ impl AstNode { for _ in 0..depth { print!("\t",); } - match *self { - AstNode::Leaf { - ref token_idx, - ref value, - } => println!( + match self { + AstNode::Leaf { token_idx, value } => println!( "Leaf( {} ) at #{} ( evaluate -> {:?} )", value, token_idx, self.evaluate() ), AstNode::Node { - ref token_idx, - ref op_type, - ref operands, + token_idx, + op_type, + operands, } => { println!( "Node( {} ) at #{} (evaluate -> {:?})", @@ -81,36 +80,33 @@ impl AstNode { }) } pub fn evaluate(&self) -> Result { - match *self { - AstNode::Leaf { ref value, .. } => Ok(value.clone()), - AstNode::Node { ref op_type, .. } => match self.operand_values() { + match self { + AstNode::Leaf { value, .. } => Ok(value.clone()), + AstNode::Node { op_type, .. } => match self.operand_values() { Err(reason) => Err(reason), Ok(operand_values) => match op_type.as_ref() { - "+" => infix_operator_two_ints( - |a: i64, b: i64| checked_binop(|| a.checked_add(b), "+"), - &operand_values, - ), - "-" => infix_operator_two_ints( - |a: i64, b: i64| checked_binop(|| a.checked_sub(b), "-"), - &operand_values, - ), - "*" => infix_operator_two_ints( - |a: i64, b: i64| checked_binop(|| a.checked_mul(b), "*"), - &operand_values, - ), + "+" => { + infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a + b), &operand_values) + } + "-" => { + infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a - b), &operand_values) + } + "*" => { + infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a * b), &operand_values) + } "/" => infix_operator_two_ints( - |a: i64, b: i64| { - if b == 0 { + |a: BigInt, b: BigInt| { + if b.is_zero() { Err("division by zero".to_owned()) } else { - checked_binop(|| a.checked_div(b), "/") + Ok(a / b) } }, &operand_values, ), "%" => infix_operator_two_ints( - |a: i64, b: i64| { - if b == 0 { + |a: BigInt, b: BigInt| { + if b.is_zero() { Err("division by zero".to_owned()) } else { Ok(a % b) @@ -119,32 +115,32 @@ impl AstNode { &operand_values, ), "=" => infix_operator_two_ints_or_two_strings( - |a: i64, b: i64| Ok(bool_as_int(a == b)), + |a: BigInt, b: BigInt| Ok(bool_as_int(a == b)), |a: &String, b: &String| Ok(bool_as_string(a == b)), &operand_values, ), "!=" => infix_operator_two_ints_or_two_strings( - |a: i64, b: i64| Ok(bool_as_int(a != b)), + |a: BigInt, b: BigInt| Ok(bool_as_int(a != b)), |a: &String, b: &String| Ok(bool_as_string(a != b)), &operand_values, ), "<" => infix_operator_two_ints_or_two_strings( - |a: i64, b: i64| Ok(bool_as_int(a < b)), + |a: BigInt, b: BigInt| Ok(bool_as_int(a < b)), |a: &String, b: &String| Ok(bool_as_string(a < b)), &operand_values, ), ">" => infix_operator_two_ints_or_two_strings( - |a: i64, b: i64| Ok(bool_as_int(a > b)), + |a: BigInt, b: BigInt| Ok(bool_as_int(a > b)), |a: &String, b: &String| Ok(bool_as_string(a > b)), &operand_values, ), "<=" => infix_operator_two_ints_or_two_strings( - |a: i64, b: i64| Ok(bool_as_int(a <= b)), + |a: BigInt, b: BigInt| Ok(bool_as_int(a <= b)), |a: &String, b: &String| Ok(bool_as_string(a <= b)), &operand_values, ), ">=" => infix_operator_two_ints_or_two_strings( - |a: i64, b: i64| Ok(bool_as_int(a >= b)), + |a: BigInt, b: BigInt| Ok(bool_as_int(a >= b)), |a: &String, b: &String| Ok(bool_as_string(a >= b)), &operand_values, ), @@ -161,7 +157,7 @@ impl AstNode { } } pub fn operand_values(&self) -> Result, String> { - if let AstNode::Node { ref operands, .. } = *self { + if let AstNode::Node { operands, .. } = self { let mut out = Vec::with_capacity(operands.len()); for operand in operands { match operand.evaluate() { @@ -217,9 +213,9 @@ fn maybe_dump_ast(result: &Result, String>) { if let Ok(debug_var) = env::var("EXPR_DEBUG_AST") { if debug_var == "1" { println!("EXPR_DEBUG_AST"); - match *result { - Ok(ref ast) => ast.debug_dump(), - Err(ref reason) => println!("\terr: {:?}", reason), + match result { + Ok(ast) => ast.debug_dump(), + Err(reason) => println!("\terr: {:?}", reason), } } } @@ -304,7 +300,7 @@ fn push_token_to_either_stack( out_stack: &mut TokenStack, op_stack: &mut TokenStack, ) -> Result<(), String> { - let result = match *token { + let result = match token { Token::Value { .. } => { out_stack.push((token_idx, token.clone())); Ok(()) @@ -420,24 +416,14 @@ fn move_till_match_paren( } } -fn checked_binop Option, T>(cb: F, op: &str) -> Result { - match cb() { - Some(v) => Ok(v), - None => Err(format!("{}: Numerical result out of range", op)), - } -} - fn infix_operator_two_ints(f: F, values: &[String]) -> Result where - F: Fn(i64, i64) -> Result, + F: Fn(BigInt, BigInt) -> Result, { assert!(values.len() == 2); - if let Ok(left) = values[0].parse::() { - if let Ok(right) = values[1].parse::() { - return match f(left, right) { - Ok(result) => Ok(result.to_string()), - Err(reason) => Err(reason), - }; + if let Ok(left) = values[0].parse::() { + if let Ok(right) = values[1].parse::() { + return f(left, right).map(|big_int| big_int.to_string()); } } Err("Expected an integer operand".to_string()) @@ -449,13 +435,14 @@ fn infix_operator_two_ints_or_two_strings( values: &[String], ) -> Result where - FI: Fn(i64, i64) -> Result, + FI: Fn(BigInt, BigInt) -> Result, FS: Fn(&String, &String) -> Result, { assert!(values.len() == 2); - if let (Some(a_int), Some(b_int)) = - (values[0].parse::().ok(), values[1].parse::().ok()) - { + if let (Some(a_int), Some(b_int)) = ( + values[0].parse::().ok(), + values[1].parse::().ok(), + ) { match fi(a_int, b_int) { Ok(result) => Ok(result.to_string()), Err(reason) => Err(reason), @@ -541,7 +528,7 @@ fn prefix_operator_substr(values: &[String]) -> String { subj.chars().skip(idx).take(len).collect() } -fn bool_as_int(b: bool) -> i64 { +fn bool_as_int(b: bool) -> u8 { if b { 1 } else { @@ -559,8 +546,8 @@ fn value_as_bool(s: &str) -> bool { if s.is_empty() { return false; } - match s.parse::() { - Ok(n) => n != 0, + match s.parse::() { + Ok(n) => n.is_one(), Err(_) => true, } } diff --git a/src/uu/expr/src/tokens.rs b/src/uu/expr/src/tokens.rs index 6056e4ba1..6f2795588 100644 --- a/src/uu/expr/src/tokens.rs +++ b/src/uu/expr/src/tokens.rs @@ -18,6 +18,8 @@ // spell-checker:ignore (ToDO) paren +use num_bigint::BigInt; + #[derive(Debug, Clone)] pub enum Token { Value { @@ -51,14 +53,14 @@ impl Token { } fn is_infix_plus(&self) -> bool { - match *self { - Token::InfixOp { ref value, .. } => value == "+", + match self { + Token::InfixOp { value, .. } => value == "+", _ => false, } } fn is_a_number(&self) -> bool { - match *self { - Token::Value { ref value, .. } => value.parse::().is_ok(), + match self { + Token::Value { value, .. } => value.parse::().is_ok(), _ => false, } } @@ -142,7 +144,7 @@ fn push_token_if_not_escaped(acc: &mut Vec<(usize, Token)>, tok_idx: usize, toke // Smells heuristics... :( let prev_is_plus = match acc.last() { None => false, - Some(ref t) => t.1.is_infix_plus(), + Some(t) => t.1.is_infix_plus(), }; let should_use_as_escaped = if prev_is_plus && acc.len() >= 2 { let pre_prev = &acc[acc.len() - 2]; diff --git a/tests/by-util/test_expr.rs b/tests/by-util/test_expr.rs index f20739e13..30e3016a3 100644 --- a/tests/by-util/test_expr.rs +++ b/tests/by-util/test_expr.rs @@ -2,55 +2,95 @@ use crate::common::util::*; #[test] fn test_simple_arithmetic() { - new_ucmd!().args(&["1", "+", "1"]).run().stdout_is("2\n"); + new_ucmd!() + .args(&["1", "+", "1"]) + .succeeds() + .stdout_only("2\n"); - new_ucmd!().args(&["1", "-", "1"]).run().stdout_is("0\n"); + new_ucmd!() + .args(&["1", "-", "1"]) + .fails() + .status_code(1) + .stdout_only("0\n"); - new_ucmd!().args(&["3", "*", "2"]).run().stdout_is("6\n"); + new_ucmd!() + .args(&["3", "*", "2"]) + .succeeds() + .stdout_only("6\n"); - new_ucmd!().args(&["4", "/", "2"]).run().stdout_is("2\n"); + new_ucmd!() + .args(&["4", "/", "2"]) + .succeeds() + .stdout_only("2\n"); } #[test] fn test_complex_arithmetic() { - let run = new_ucmd!() + new_ucmd!() .args(&["9223372036854775807", "+", "9223372036854775807"]) - .run(); - run.stdout_is(""); - run.stderr_is("expr: +: Numerical result out of range"); + .succeeds() + .stdout_only("18446744073709551614\n"); - let run = new_ucmd!().args(&["9", "/", "0"]).run(); - run.stdout_is(""); - run.stderr_is("expr: division by zero"); + new_ucmd!() + .args(&[ + "92233720368547758076549841651981984981498415651", + "%", + "922337203685", + ]) + .succeeds() + .stdout_only("533691697086\n"); + + new_ucmd!() + .args(&[ + "92233720368547758076549841651981984981498415651", + "*", + "922337203685", + ]) + .succeeds() + .stdout_only("85070591730190566808700855121818604965830915152801178873935\n"); + + new_ucmd!() + .args(&[ + "92233720368547758076549841651981984981498415651", + "-", + "922337203685", + ]) + .succeeds() + .stdout_only("92233720368547758076549841651981984059161211966\n"); + + new_ucmd!() + .args(&["9", "/", "0"]) + .fails() + .stderr_only("expr: division by zero\n"); } #[test] fn test_parenthesis() { new_ucmd!() .args(&["(", "1", "+", "1", ")", "*", "2"]) - .run() - .stdout_is("4\n"); + .succeeds() + .stdout_only("4\n"); } #[test] fn test_or() { new_ucmd!() .args(&["0", "|", "foo"]) - .run() - .stdout_is("foo\n"); + .succeeds() + .stdout_only("foo\n"); new_ucmd!() .args(&["foo", "|", "bar"]) - .run() - .stdout_is("foo\n"); + .succeeds() + .stdout_only("foo\n"); } #[test] fn test_and() { new_ucmd!() .args(&["foo", "&", "1"]) - .run() - .stdout_is("foo\n"); + .succeeds() + .stdout_only("foo\n"); new_ucmd!().args(&["", "&", "1"]).run().stdout_is("0\n"); } From dc63133f1449b45d2068555935322101a0a4acff Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Sat, 29 May 2021 23:25:56 +0200 Subject: [PATCH 30/39] sort: correctly inherit global flags for keys (#2302) Closes #2254. We should only inherit global settings for keys when there are absolutely no options attached to the key. The default key (matching the whole line) is implicitly added only if no keys are supplied. Improved some error messages by including more context. --- src/uu/sort/BENCHMARKING.md | 2 +- src/uu/sort/src/sort.rs | 366 ++++++++++++------ tests/by-util/test_sort.rs | 57 ++- tests/fixtures/sort/blanks.expected | 5 + tests/fixtures/sort/blanks.expected.debug | 15 + tests/fixtures/sort/blanks.txt | 5 + tests/fixtures/sort/keys_ignore_flag.expected | 2 + .../sort/keys_ignore_flag.expected.debug | 6 + tests/fixtures/sort/keys_ignore_flag.txt | 2 + 9 files changed, 331 insertions(+), 129 deletions(-) create mode 100644 tests/fixtures/sort/blanks.expected create mode 100644 tests/fixtures/sort/blanks.expected.debug create mode 100644 tests/fixtures/sort/blanks.txt create mode 100644 tests/fixtures/sort/keys_ignore_flag.expected create mode 100644 tests/fixtures/sort/keys_ignore_flag.expected.debug create mode 100644 tests/fixtures/sort/keys_ignore_flag.txt diff --git a/src/uu/sort/BENCHMARKING.md b/src/uu/sort/BENCHMARKING.md index fd728c41d..560d6b438 100644 --- a/src/uu/sort/BENCHMARKING.md +++ b/src/uu/sort/BENCHMARKING.md @@ -2,7 +2,7 @@ Most of the time when sorting is spent comparing lines. The comparison functions however differ based on which arguments are passed to `sort`, therefore it is important to always benchmark multiple scenarios. -This is an overwiew over what was benchmarked, and if you make changes to `sort`, you are encouraged to check +This is an overview over what was benchmarked, and if you make changes to `sort`, you are encouraged to check how performance was affected for the workloads listed below. Feel free to add other workloads to the list that we should improve / make sure not to regress. diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 5fdaf32cf..a3b79e5d7 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -108,7 +108,7 @@ const POSITIVE: char = '+'; // available memory into consideration, instead of relying on this constant only. static DEFAULT_BUF_SIZE: usize = 1_000_000_000; // 1 GB -#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Copy)] +#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Copy, Debug)] enum SortMode { Numeric, HumanNumeric, @@ -118,6 +118,21 @@ enum SortMode { Random, Default, } + +impl SortMode { + fn get_short_name(&self) -> Option { + match self { + SortMode::Numeric => Some('n'), + SortMode::HumanNumeric => Some('h'), + SortMode::GeneralNumeric => Some('g'), + SortMode::Month => Some('M'), + SortMode::Version => Some('V'), + SortMode::Random => Some('R'), + SortMode::Default => None, + } + } +} + #[derive(Clone)] pub struct GlobalSettings { mode: SortMode, @@ -211,7 +226,7 @@ impl Default for GlobalSettings { } } } -#[derive(Clone)] +#[derive(Clone, PartialEq, Debug)] struct KeySettings { mode: SortMode, ignore_blanks: bool, @@ -221,6 +236,60 @@ struct KeySettings { reverse: bool, } +impl KeySettings { + /// Checks if the supplied combination of `mode`, `ignore_non_printing` and `dictionary_order` is allowed. + fn check_compatibility( + mode: SortMode, + ignore_non_printing: bool, + dictionary_order: bool, + ) -> Result<(), String> { + if matches!( + mode, + SortMode::Numeric | SortMode::HumanNumeric | SortMode::GeneralNumeric | SortMode::Month + ) { + if dictionary_order { + return Err(format!( + "options '-{}{}' are incompatible", + 'd', + mode.get_short_name().unwrap() + )); + } else if ignore_non_printing { + return Err(format!( + "options '-{}{}' are incompatible", + 'i', + mode.get_short_name().unwrap() + )); + } + } + Ok(()) + } + + fn set_sort_mode(&mut self, mode: SortMode) -> Result<(), String> { + if self.mode != SortMode::Default { + return Err(format!( + "options '-{}{}' are incompatible", + self.mode.get_short_name().unwrap(), + mode.get_short_name().unwrap() + )); + } + Self::check_compatibility(mode, self.ignore_non_printing, self.dictionary_order)?; + self.mode = mode; + Ok(()) + } + + fn set_dictionary_order(&mut self) -> Result<(), String> { + Self::check_compatibility(self.mode, self.ignore_non_printing, true)?; + self.dictionary_order = true; + Ok(()) + } + + fn set_ignore_non_printing(&mut self) -> Result<(), String> { + Self::check_compatibility(self.mode, true, self.dictionary_order)?; + self.ignore_non_printing = true; + Ok(()) + } +} + impl From<&GlobalSettings> for KeySettings { fn from(settings: &GlobalSettings) -> Self { Self { @@ -234,6 +303,12 @@ impl From<&GlobalSettings> for KeySettings { } } +impl Default for KeySettings { + fn default() -> Self { + Self::from(&GlobalSettings::default()) + } +} + #[derive(Clone, Debug)] enum NumCache { AsF64(GeneralF64ParseResult), @@ -412,14 +487,18 @@ impl<'a> Line<'a> { } } } - if !(settings.mode == SortMode::Random - || settings.stable - || settings.unique - || !(settings.dictionary_order + if settings.mode != SortMode::Random + && !settings.stable + && !settings.unique + && (settings.dictionary_order || settings.ignore_blanks || settings.ignore_case || settings.ignore_non_printing - || settings.mode != SortMode::Default)) + || settings.mode != SortMode::Default + || settings + .selectors + .last() + .map_or(true, |selector| selector != &Default::default())) { // A last resort comparator is in use, underline the whole line. if self.line.is_empty() { @@ -483,7 +562,7 @@ fn tokenize_with_separator(line: &str, separator: char) -> Vec { tokens } -#[derive(Clone)] +#[derive(Clone, PartialEq, Debug)] struct KeyPosition { /// 1-indexed, 0 is invalid. field: usize, @@ -493,87 +572,45 @@ struct KeyPosition { } impl KeyPosition { - fn parse(key: &str, default_char_index: usize, settings: &mut KeySettings) -> Self { + fn new(key: &str, default_char_index: usize, ignore_blanks: bool) -> Result { let mut field_and_char = key.split('.'); - let mut field = field_and_char + + let field = field_and_char .next() - .unwrap_or_else(|| crash!(1, "invalid key `{}`", key)); - let mut char = field_and_char.next(); - - // If there is a char index, we expect options to appear after it. Otherwise we expect them after the field index. - let value_with_options = char.as_mut().unwrap_or(&mut field); - - let mut ignore_blanks = settings.ignore_blanks; - if let Some(options_start) = value_with_options.chars().position(char::is_alphabetic) { - for option in value_with_options[options_start..].chars() { - // valid options: MbdfghinRrV - match option { - 'M' => settings.mode = SortMode::Month, - 'b' => ignore_blanks = true, - 'd' => settings.dictionary_order = true, - 'f' => settings.ignore_case = true, - 'g' => settings.mode = SortMode::GeneralNumeric, - 'h' => settings.mode = SortMode::HumanNumeric, - 'i' => settings.ignore_non_printing = true, - 'n' => settings.mode = SortMode::Numeric, - 'R' => settings.mode = SortMode::Random, - 'r' => settings.reverse = true, - 'V' => settings.mode = SortMode::Version, - c => crash!(1, "invalid option for key: `{}`", c), - } - // All numeric sorts and month sort conflict with dictionary_order and ignore_non_printing. - // Instad of reporting an error, let them overwrite each other. - - // FIXME: This should only override if the overridden flag is a global flag. - // If conflicting flags are attached to the key, GNU sort crashes and we should probably too. - match option { - 'h' | 'n' | 'g' | 'M' => { - settings.dictionary_order = false; - settings.ignore_non_printing = false; - } - 'd' | 'i' => { - settings.mode = match settings.mode { - SortMode::Numeric - | SortMode::HumanNumeric - | SortMode::GeneralNumeric - | SortMode::Month => SortMode::Default, - // Only SortMode::Default and SortMode::Version work with dictionary_order and ignore_non_printing - m @ SortMode::Default - | m @ SortMode::Version - | m @ SortMode::Random => m, - } - } - _ => {} - } - } - // Strip away option characters from the original value so we can parse it later - *value_with_options = &value_with_options[..options_start]; - } + .ok_or_else(|| format!("invalid key `{}`", key))?; + let char = field_and_char.next(); let field = field .parse() - .unwrap_or_else(|e| crash!(1, "failed to parse field index for key `{}`: {}", key, e)); + .map_err(|e| format!("failed to parse field index `{}`: {}", field, e))?; if field == 0 { - crash!(1, "field index was 0"); + return Err("field index can not be 0".to_string()); } - let char = char.map_or(default_char_index, |char| { - char.parse().unwrap_or_else(|e| { - crash!( - 1, - "failed to parse character index for key `{}`: {}", - key, - e - ) - }) - }); - Self { + + let char = char.map_or(Ok(default_char_index), |char| { + char.parse() + .map_err(|e| format!("failed to parse character index `{}`: {}", char, e)) + })?; + + Ok(Self { field, char, ignore_blanks, + }) + } +} + +impl Default for KeyPosition { + fn default() -> Self { + KeyPosition { + field: 1, + char: 1, + ignore_blanks: false, } } } -#[derive(Clone)] + +#[derive(Clone, PartialEq, Debug)] struct FieldSelector { from: KeyPosition, to: Option, @@ -583,20 +620,120 @@ struct FieldSelector { is_default_selection: bool, } -impl FieldSelector { - fn new(from: KeyPosition, to: Option, settings: KeySettings) -> Self { +impl Default for FieldSelector { + fn default() -> Self { Self { - is_default_selection: from.field == 1 - && from.char == 1 - && to.is_none() - && !matches!( - settings.mode, - SortMode::Numeric | SortMode::GeneralNumeric | SortMode::HumanNumeric - ), - needs_tokens: from.field != 1 || from.char == 0 || to.is_some(), - from, - to, - settings, + from: Default::default(), + to: None, + settings: Default::default(), + needs_tokens: false, + is_default_selection: true, + } + } +} + +impl FieldSelector { + /// Splits this position into the actual position and the attached options. + fn split_key_options(position: &str) -> (&str, &str) { + if let Some((options_start, _)) = position.char_indices().find(|(_, c)| c.is_alphabetic()) { + position.split_at(options_start) + } else { + (position, "") + } + } + + fn parse(key: &str, global_settings: &GlobalSettings) -> Self { + let mut from_to = key.split(','); + let (from, from_options) = Self::split_key_options(from_to.next().unwrap()); + let to = from_to.next().map(|to| Self::split_key_options(to)); + let options_are_empty = from_options.is_empty() && matches!(to, None | Some((_, ""))); + crash_if_err!( + 2, + if options_are_empty { + // Inherit the global settings if there are no options attached to this key. + (|| { + // This would be ideal for a try block, I think. In the meantime this closure allows + // to use the `?` operator here. + Self::new( + KeyPosition::new(from, 1, global_settings.ignore_blanks)?, + to.map(|(to, _)| KeyPosition::new(to, 0, global_settings.ignore_blanks)) + .transpose()?, + KeySettings::from(global_settings), + ) + })() + } else { + // Do not inherit from `global_settings`, as there are options attached to this key. + Self::parse_with_options((from, from_options), to) + } + .map_err(|e| format!("failed to parse key `{}`: {}", key, e)) + ) + } + + fn parse_with_options( + (from, from_options): (&str, &str), + to: Option<(&str, &str)>, + ) -> Result { + /// Applies `options` to `key_settings`, returning if the 'b'-flag (ignore blanks) was present. + fn parse_key_settings( + options: &str, + key_settings: &mut KeySettings, + ) -> Result { + let mut ignore_blanks = false; + for option in options.chars() { + match option { + 'M' => key_settings.set_sort_mode(SortMode::Month)?, + 'b' => ignore_blanks = true, + 'd' => key_settings.set_dictionary_order()?, + 'f' => key_settings.ignore_case = true, + 'g' => key_settings.set_sort_mode(SortMode::GeneralNumeric)?, + 'h' => key_settings.set_sort_mode(SortMode::HumanNumeric)?, + 'i' => key_settings.set_ignore_non_printing()?, + 'n' => key_settings.set_sort_mode(SortMode::Numeric)?, + 'R' => key_settings.set_sort_mode(SortMode::Random)?, + 'r' => key_settings.reverse = true, + 'V' => key_settings.set_sort_mode(SortMode::Version)?, + c => return Err(format!("invalid option: `{}`", c)), + } + } + Ok(ignore_blanks) + } + + let mut key_settings = KeySettings::default(); + let from = parse_key_settings(from_options, &mut key_settings) + .map(|ignore_blanks| KeyPosition::new(from, 1, ignore_blanks))??; + let to = if let Some((to, to_options)) = to { + Some( + parse_key_settings(to_options, &mut key_settings) + .map(|ignore_blanks| KeyPosition::new(to, 0, ignore_blanks))??, + ) + } else { + None + }; + Self::new(from, to, key_settings) + } + + fn new( + from: KeyPosition, + to: Option, + settings: KeySettings, + ) -> Result { + if from.char == 0 { + Err("invalid character index 0 for the start position of a field".to_string()) + } else { + Ok(Self { + is_default_selection: from.field == 1 + && from.char == 1 + && to.is_none() + && !matches!( + settings.mode, + SortMode::Numeric | SortMode::GeneralNumeric | SortMode::HumanNumeric + ) + && !from.ignore_blanks, + needs_tokens: from.field != 1 || from.char == 0 || to.is_some(), + from, + to, + settings, + }) } } @@ -900,7 +1037,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .long(OPT_SEPARATOR) .help("custom separator for -k") .takes_value(true)) - .arg(Arg::with_name(OPT_ZERO_TERMINATED) + .arg( + Arg::with_name(OPT_ZERO_TERMINATED) .short("z") .long(OPT_ZERO_TERMINATED) .help("line delimiter is NUL, not newline"), @@ -1053,43 +1191,27 @@ pub fn uumain(args: impl uucore::Args) -> i32 { if matches.is_present(OPT_KEY) { for key in &matches.args[OPT_KEY].vals { - let key = key.to_string_lossy(); - let mut from_to = key.split(','); - let mut key_settings = KeySettings::from(&settings); - let from = KeyPosition::parse( - from_to - .next() - .unwrap_or_else(|| crash!(1, "invalid key `{}`", key)), - 1, - &mut key_settings, - ); - if from.char == 0 { - crash!( - 1, - "invalid character index 0 in `{}` for the start position of a field", - key - ) - } - let to = from_to - .next() - .map(|to| KeyPosition::parse(to, 0, &mut key_settings)); - let field_selector = FieldSelector::new(from, to, key_settings); - settings.selectors.push(field_selector); + settings + .selectors + .push(FieldSelector::parse(&key.to_string_lossy(), &settings)); } } - if !settings.stable || !matches.is_present(OPT_KEY) { + if !matches.is_present(OPT_KEY) { // add a default selector matching the whole line let key_settings = KeySettings::from(&settings); - settings.selectors.push(FieldSelector::new( - KeyPosition { - field: 1, - char: 1, - ignore_blanks: key_settings.ignore_blanks, - }, - None, - key_settings, - )); + settings.selectors.push( + FieldSelector::new( + KeyPosition { + field: 1, + char: 1, + ignore_blanks: key_settings.ignore_blanks, + }, + None, + key_settings, + ) + .unwrap(), + ); } exec(&files, &settings) diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index 6a2350749..588ce86bd 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -471,7 +471,7 @@ fn test_keys_invalid_field() { new_ucmd!() .args(&["-k", "1."]) .fails() - .stderr_only("sort: failed to parse character index for key `1.`: cannot parse integer from empty string"); + .stderr_only("sort: failed to parse key `1.`: failed to parse character index ``: cannot parse integer from empty string"); } #[test] @@ -479,7 +479,7 @@ fn test_keys_invalid_field_option() { new_ucmd!() .args(&["-k", "1.1x"]) .fails() - .stderr_only("sort: invalid option for key: `x`"); + .stderr_only("sort: failed to parse key `1.1x`: invalid option: `x`"); } #[test] @@ -487,7 +487,7 @@ fn test_keys_invalid_field_zero() { new_ucmd!() .args(&["-k", "0.1"]) .fails() - .stderr_only("sort: field index was 0"); + .stderr_only("sort: failed to parse key `0.1`: field index can not be 0"); } #[test] @@ -495,7 +495,7 @@ fn test_keys_invalid_char_zero() { new_ucmd!() .args(&["-k", "1.0"]) .fails() - .stderr_only("sort: invalid character index 0 in `1.0` for the start position of a field"); + .stderr_only("sort: failed to parse key `1.0`: invalid character index 0 for the start position of a field"); } #[test] @@ -586,6 +586,47 @@ fn test_keys_negative_size_match() { test_helper("keys_negative_size", &["-k 3,1"]); } +#[test] +fn test_keys_ignore_flag() { + test_helper("keys_ignore_flag", &["-k 1n -b"]) +} + +#[test] +fn test_doesnt_inherit_key_settings() { + let input = " 1 +2 + 10 +"; + new_ucmd!() + .args(&["-k", "1b", "-n"]) + .pipe_in(input) + .succeeds() + .stdout_only( + " 1 + 10 +2 +", + ); +} + +#[test] +fn test_inherits_key_settings() { + let input = " 1 +2 + 10 +"; + new_ucmd!() + .args(&["-k", "1", "-n"]) + .pipe_in(input) + .succeeds() + .stdout_only( + " 1 +2 + 10 +", + ); +} + #[test] fn test_zero_terminated() { test_helper("zero-terminated", &["-z"]); @@ -707,10 +748,9 @@ fn test_dictionary_and_nonprinting_conflicts() { .succeeds(); } for conflicting_arg in &conflicting_args { - // FIXME: this should ideally fail. new_ucmd!() .args(&["-k", &format!("1{},1{}", restricted_arg, conflicting_arg)]) - .succeeds(); + .fails(); } } } @@ -737,3 +777,8 @@ fn test_nonexistent_file() { "sort: cannot read: \"nonexistent.txt\": The system cannot find the file specified. (os error 2)", ); } + +#[test] +fn test_blanks() { + test_helper("blanks", &["-b", "--ignore-blanks"]); +} diff --git a/tests/fixtures/sort/blanks.expected b/tests/fixtures/sort/blanks.expected new file mode 100644 index 000000000..3469e434c --- /dev/null +++ b/tests/fixtures/sort/blanks.expected @@ -0,0 +1,5 @@ + a +b + x + x + z diff --git a/tests/fixtures/sort/blanks.expected.debug b/tests/fixtures/sort/blanks.expected.debug new file mode 100644 index 000000000..28c8fc960 --- /dev/null +++ b/tests/fixtures/sort/blanks.expected.debug @@ -0,0 +1,15 @@ + a + _ +___ +b +_ +_ + x + _ +__________ + x + _ +___ + z + _ +__ diff --git a/tests/fixtures/sort/blanks.txt b/tests/fixtures/sort/blanks.txt new file mode 100644 index 000000000..eb2f3c94e --- /dev/null +++ b/tests/fixtures/sort/blanks.txt @@ -0,0 +1,5 @@ +b + a + z + x + x diff --git a/tests/fixtures/sort/keys_ignore_flag.expected b/tests/fixtures/sort/keys_ignore_flag.expected new file mode 100644 index 000000000..964d04663 --- /dev/null +++ b/tests/fixtures/sort/keys_ignore_flag.expected @@ -0,0 +1,2 @@ + 1a +1A diff --git a/tests/fixtures/sort/keys_ignore_flag.expected.debug b/tests/fixtures/sort/keys_ignore_flag.expected.debug new file mode 100644 index 000000000..6d0da711f --- /dev/null +++ b/tests/fixtures/sort/keys_ignore_flag.expected.debug @@ -0,0 +1,6 @@ + 1a + _ +___ +1A +_ +__ diff --git a/tests/fixtures/sort/keys_ignore_flag.txt b/tests/fixtures/sort/keys_ignore_flag.txt new file mode 100644 index 000000000..964d04663 --- /dev/null +++ b/tests/fixtures/sort/keys_ignore_flag.txt @@ -0,0 +1,2 @@ + 1a +1A From 5b417e251d80a5d5652fea05ffcfccb9992243cf Mon Sep 17 00:00:00 2001 From: Dean Li Date: Sun, 30 May 2021 10:45:54 +0800 Subject: [PATCH 31/39] rmdir: match GNU error output Related to #2258 --- src/uu/rmdir/src/rmdir.rs | 6 ++++++ tests/by-util/test_rmdir.rs | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/uu/rmdir/src/rmdir.rs b/src/uu/rmdir/src/rmdir.rs index 7a7e8fc9b..6f0a2ffa9 100644 --- a/src/uu/rmdir/src/rmdir.rs +++ b/src/uu/rmdir/src/rmdir.rs @@ -20,6 +20,8 @@ static OPT_VERBOSE: &str = "verbose"; static ARG_DIRS: &str = "dirs"; +static ENOTDIR: i32 = 20; + fn get_usage() -> String { format!("{0} [OPTION]... DIRECTORY...", executable!()) } @@ -105,6 +107,10 @@ fn remove(dirs: Vec, ignore: bool, parents: bool, verbose: bool) -> Resu fn remove_dir(path: &Path, ignore: bool, verbose: bool) -> Result<(), i32> { let mut read_dir = match fs::read_dir(path) { Ok(m) => m, + Err(e) if e.raw_os_error() == Some(ENOTDIR) => { + show_error!("failed to remove '{}': Not a directory", path.display()); + return Err(1); + } Err(e) => { show_error!("reading directory '{}': {}", path.display(), e); return Err(1); diff --git a/tests/by-util/test_rmdir.rs b/tests/by-util/test_rmdir.rs index eef2d50f5..4b74b2522 100644 --- a/tests/by-util/test_rmdir.rs +++ b/tests/by-util/test_rmdir.rs @@ -108,3 +108,19 @@ fn test_rmdir_ignore_nonempty_directory_with_parents() { assert!(at.dir_exists(dir)); } + +#[test] +fn test_rmdir_remove_symlink_match_gnu_error() { + let (at, mut ucmd) = at_and_ucmd!(); + + let file = "file"; + let fl = "fl"; + at.touch(file); + assert!(at.file_exists(file)); + at.symlink_file(file, fl); + assert!(at.file_exists(fl)); + + ucmd.arg("fl/") + .fails() + .stderr_is("rmdir: failed to remove 'fl/': Not a directory"); +} From 83bb8795bd75aaae907d5b339e50ef64279ed82e Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 30 May 2021 09:16:46 +0200 Subject: [PATCH 32/39] add a comment to explain the why --- src/uu/rmdir/src/rmdir.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/uu/rmdir/src/rmdir.rs b/src/uu/rmdir/src/rmdir.rs index 6f0a2ffa9..6b6db0b65 100644 --- a/src/uu/rmdir/src/rmdir.rs +++ b/src/uu/rmdir/src/rmdir.rs @@ -108,6 +108,7 @@ fn remove_dir(path: &Path, ignore: bool, verbose: bool) -> Result<(), i32> { let mut read_dir = match fs::read_dir(path) { Ok(m) => m, Err(e) if e.raw_os_error() == Some(ENOTDIR) => { + // To match the GNU output show_error!("failed to remove '{}': Not a directory", path.display()); return Err(1); } From 3913731222ce263b3deb3991bfd36668eac610c2 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 30 May 2021 09:55:02 +0200 Subject: [PATCH 33/39] Revert "rmdir: match GNU error output" --- src/uu/rmdir/src/rmdir.rs | 7 ------- tests/by-util/test_rmdir.rs | 16 ---------------- 2 files changed, 23 deletions(-) diff --git a/src/uu/rmdir/src/rmdir.rs b/src/uu/rmdir/src/rmdir.rs index 6b6db0b65..7a7e8fc9b 100644 --- a/src/uu/rmdir/src/rmdir.rs +++ b/src/uu/rmdir/src/rmdir.rs @@ -20,8 +20,6 @@ static OPT_VERBOSE: &str = "verbose"; static ARG_DIRS: &str = "dirs"; -static ENOTDIR: i32 = 20; - fn get_usage() -> String { format!("{0} [OPTION]... DIRECTORY...", executable!()) } @@ -107,11 +105,6 @@ fn remove(dirs: Vec, ignore: bool, parents: bool, verbose: bool) -> Resu fn remove_dir(path: &Path, ignore: bool, verbose: bool) -> Result<(), i32> { let mut read_dir = match fs::read_dir(path) { Ok(m) => m, - Err(e) if e.raw_os_error() == Some(ENOTDIR) => { - // To match the GNU output - show_error!("failed to remove '{}': Not a directory", path.display()); - return Err(1); - } Err(e) => { show_error!("reading directory '{}': {}", path.display(), e); return Err(1); diff --git a/tests/by-util/test_rmdir.rs b/tests/by-util/test_rmdir.rs index 4b74b2522..eef2d50f5 100644 --- a/tests/by-util/test_rmdir.rs +++ b/tests/by-util/test_rmdir.rs @@ -108,19 +108,3 @@ fn test_rmdir_ignore_nonempty_directory_with_parents() { assert!(at.dir_exists(dir)); } - -#[test] -fn test_rmdir_remove_symlink_match_gnu_error() { - let (at, mut ucmd) = at_and_ucmd!(); - - let file = "file"; - let fl = "fl"; - at.touch(file); - assert!(at.file_exists(file)); - at.symlink_file(file, fl); - assert!(at.file_exists(fl)); - - ucmd.arg("fl/") - .fails() - .stderr_is("rmdir: failed to remove 'fl/': Not a directory"); -} From 141a92c9650046de7178e93008b77c3013a6dc34 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sun, 30 May 2021 09:29:10 +0200 Subject: [PATCH 34/39] CI: set clippy targets to 'all' --- .github/workflows/CICD.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 72682ff03..5ac9295d4 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -84,7 +84,7 @@ jobs: - name: Install `rust` toolchain uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: nightly default: true profile: minimal # minimal component installation (ie, no documentation) components: clippy @@ -94,7 +94,7 @@ jobs: run: | # `clippy` testing # * convert any warnings to GHA UI annotations; ref: - S=$(cargo +nightly clippy --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -- -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::warning file=\2,line=\3,col=\4::WARNING: \`cargo clippy\`: \1/p;" -e '}' ; } + S=$(cargo +nightly clippy --all-targets ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -- -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::warning file=\2,line=\3,col=\4::WARNING: \`cargo clippy\`: \1/p;" -e '}' ; } min_version: name: MinRustV # Minimum supported rust version From cda04eb690520d938c1983c941209724d18f9d26 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sun, 30 May 2021 12:42:46 +0200 Subject: [PATCH 35/39] docs: add note for clippy usage --- DEVELOPER_INSTRUCTIONS.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/DEVELOPER_INSTRUCTIONS.md b/DEVELOPER_INSTRUCTIONS.md index c3b20dd46..3aa8b5b12 100644 --- a/DEVELOPER_INSTRUCTIONS.md +++ b/DEVELOPER_INSTRUCTIONS.md @@ -21,7 +21,7 @@ if changes are not reflected in the report then run `cargo clean` and run the a ### Using Stable Rust -If you are using stable version of Rust that doesn't enable code coverage instrumentation by default +If you are using stable version of Rust that doesn't enable code coverage instrumentation by default then add `-Z-Zinstrument-coverage` flag to `RUSTFLAGS` env variable specified above. @@ -36,3 +36,7 @@ To use the provided hook: 2. Run `pre-commit install` while in the repository directory Your git commits will then automatically be checked. If a check fails, an error message will explain why, and your commit will be canceled. You can then make the suggested changes, and run `git commit ...` again. + +### Using Clippy + +The `msrv` key in the clippy configuration file `clippy.toml` is used to disable lints pertaining to newer features by specifying the minimum supported Rust version (MSRV). However, this key is only supported on `nightly`. To invoke clippy without errors, use `cargo +nightly clippy`. In order to also check tests and non-default crate features, use `cargo +nightly clippy --all-targets --all-features`. From 898d325aeabdbb8a76bfdcf33caf3dce134990ae Mon Sep 17 00:00:00 2001 From: Anup Mahindre Date: Sun, 30 May 2021 18:00:52 +0530 Subject: [PATCH 36/39] ls: Fix minor output mismatch When a single directory is passed to ls in recursive mode, uutils ls won't print the directory name ====================== GNU ls: z: ====================== ====================== uutils ls: ====================== This commit fixes this minor inconsistency and adds corresponding test. --- src/uu/ls/src/ls.rs | 2 +- tests/by-util/test_ls.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 60c076441..5846cb0aa 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -1223,7 +1223,7 @@ fn list(locs: Vec, config: Config) -> i32 { sort_entries(&mut dirs, &config); for dir in dirs { - if locs.len() > 1 { + if locs.len() > 1 || config.recursive { let _ = writeln!(out, "\n{}:", dir.p_buf.display()); } enter_directory(&dir, &config, &mut out); diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index d884948e6..9614f561e 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -899,6 +899,12 @@ fn test_ls_recursive() { scene.ucmd().arg("a").succeeds(); scene.ucmd().arg("a/a").succeeds(); + scene + .ucmd() + .arg("z") + .arg("-R") + .succeeds() + .stdout_contains(&"z:"); let result = scene .ucmd() .arg("--color=never") From 69850942b6dd03ebf67c5f7217ff9fee59140dfa Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 30 May 2021 16:26:00 +0200 Subject: [PATCH 37/39] fix a clippy warning WARNING: `cargo clippy`: single-character string constant used as pattern --- tests/by-util/test_du.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index c5d262c3b..e4dca7a61 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -187,7 +187,7 @@ fn test_du_d_flag() { // TODO: gnu `du` doesn't use trailing "/" here // result.stdout_str(), result_reference.stdout_str() result.stdout_str().trim_end_matches("/\n"), - result_reference.stdout_str().trim_end_matches("\n") + result_reference.stdout_str().trim_end_matches('\n') ); return; } From b9863e1cc4637f2c3eaff16ac274dce1f2e1c890 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sun, 30 May 2021 20:07:57 +0200 Subject: [PATCH 38/39] fix precommit for clippy nightly --- .pre-commit-config.yaml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 66d2a5f5a..177b6b8e3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,8 +1,16 @@ -# https://pre-commit.com -repos: - - repo: https://github.com/doublify/pre-commit-rust - rev: v1.0 +- repo: local hooks: - - id: cargo-check - - id: clippy - - id: fmt + - id: rust-linting + name: Rust linting + description: Run cargo fmt on files included in the commit. + entry: cargo +nightly fmt -- + pass_filenames: true + types: [file, rust] + language: system + - id: rust-clippy + name: Rust clippy + description: Run cargo clippy on files included in the commit. + entry: cargo +nightly clippy --all-targets --all-features -- + pass_filenames: false + types: [file, rust] + language: system From 4a3703d218131d4319a90fb3a925cdff1f4602e3 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 30 May 2021 23:18:45 +0200 Subject: [PATCH 39/39] fix a warning it was showing: [WARNING] normalizing pre-commit configuration to a top-level map. support for top level list will be removed in a future version. run: `pre-commit migrate-config` to automatically fix this. --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 177b6b8e3..e3ad98ee3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,4 @@ +repos: - repo: local hooks: - id: rust-linting