mirror of
https://github.com/uutils/coreutils
synced 2024-07-22 10:24:54 +00:00
Merge branch 'master' into ls_selinux
This commit is contained in:
commit
79d838b1c3
32
.github/workflows/CICD.yml
vendored
32
.github/workflows/CICD.yml
vendored
|
@ -708,3 +708,35 @@ jobs:
|
|||
flags: ${{ steps.vars.outputs.CODECOV_FLAGS }}
|
||||
name: codecov-umbrella
|
||||
fail_ci_if_error: false
|
||||
|
||||
unused_deps:
|
||||
name: Unused deps
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- { os: ubuntu-latest , features: feat_os_unix }
|
||||
- { os: macos-latest , features: feat_os_macos }
|
||||
- { os: windows-latest , features: feat_os_windows }
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install `rust` toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
default: true
|
||||
profile: minimal
|
||||
- name: Install `cargo-udeps`
|
||||
uses: actions-rs/install@v0.1
|
||||
with:
|
||||
crate: cargo-udeps
|
||||
version: latest
|
||||
use-tool-cache: true
|
||||
env:
|
||||
RUSTUP_TOOLCHAIN: stable
|
||||
- name: Confirms there isn't any unused deps
|
||||
shell: bash
|
||||
run: |
|
||||
cargo +nightly udeps --all-targets &> udeps.log || cat udeps.log
|
||||
grep "seem to have been used" udeps.log
|
||||
|
|
|
@ -43,6 +43,9 @@ gibi
|
|||
gibibytes
|
||||
glob
|
||||
globbing
|
||||
hardcode
|
||||
hardcoded
|
||||
hardcoding
|
||||
hardfloat
|
||||
hardlink
|
||||
hardlinks
|
||||
|
@ -114,6 +117,7 @@ toolchain
|
|||
truthy
|
||||
ucase
|
||||
unbuffered
|
||||
udeps
|
||||
unescape
|
||||
unintuitive
|
||||
unprefixed
|
||||
|
|
|
@ -68,6 +68,7 @@ structs
|
|||
substr
|
||||
splitn
|
||||
trunc
|
||||
uninit
|
||||
|
||||
# * uutils
|
||||
basenc
|
||||
|
@ -277,6 +278,7 @@ ULONG
|
|||
ULONGLONG
|
||||
UNLEN
|
||||
WCHAR
|
||||
WSADATA
|
||||
errhandlingapi
|
||||
fileapi
|
||||
handleapi
|
||||
|
|
36
Cargo.lock
generated
36
Cargo.lock
generated
|
@ -1004,15 +1004,6 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "locale"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fdbe492a9c0238da900a1165c42fc5067161ce292678a6fe80921f30fe307fd"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.4"
|
||||
|
@ -1104,19 +1095,6 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.19.1"
|
||||
|
@ -2314,7 +2292,6 @@ name = "uu_csplit"
|
|||
version = "0.0.7"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"glob",
|
||||
"regex",
|
||||
"thiserror",
|
||||
"uucore",
|
||||
|
@ -2628,7 +2605,6 @@ dependencies = [
|
|||
"clap",
|
||||
"globset",
|
||||
"lazy_static",
|
||||
"locale",
|
||||
"lscolors",
|
||||
"number_prefix",
|
||||
"once_cell",
|
||||
|
@ -2713,7 +2689,7 @@ version = "0.0.7"
|
|||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
"nix 0.13.1",
|
||||
"nix 0.20.0",
|
||||
"uucore",
|
||||
"uucore_procs",
|
||||
]
|
||||
|
@ -2813,7 +2789,6 @@ dependencies = [
|
|||
"itertools 0.10.1",
|
||||
"quick-error 2.0.1",
|
||||
"regex",
|
||||
"time",
|
||||
"uucore",
|
||||
"uucore_procs",
|
||||
]
|
||||
|
@ -2939,10 +2914,8 @@ name = "uu_shred"
|
|||
version = "0.0.7"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"filetime",
|
||||
"libc",
|
||||
"rand 0.7.3",
|
||||
"time",
|
||||
"uucore",
|
||||
"uucore_procs",
|
||||
]
|
||||
|
@ -3052,6 +3025,7 @@ version = "0.0.7"
|
|||
dependencies = [
|
||||
"clap",
|
||||
"memchr 2.4.0",
|
||||
"regex",
|
||||
"uucore",
|
||||
"uucore_procs",
|
||||
]
|
||||
|
@ -3314,12 +3288,6 @@ version = "0.9.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
|
|
|
@ -366,7 +366,6 @@ conv = "0.3"
|
|||
filetime = "0.2"
|
||||
glob = "0.3.0"
|
||||
libc = "0.2"
|
||||
nix = "0.20.0"
|
||||
pretty_assertions = "0.7.2"
|
||||
rand = "0.7"
|
||||
regex = "1.0"
|
||||
|
@ -378,8 +377,12 @@ uucore = { version=">=0.0.9", package="uucore", path="src/uucore", features=["en
|
|||
walkdir = "2.2"
|
||||
atty = "0.2"
|
||||
|
||||
[target.'cfg(unix)'.dev-dependencies]
|
||||
[target.'cfg(target_os = "linux")'.dev-dependencies]
|
||||
rlimit = "0.4.0"
|
||||
|
||||
[target.'cfg(unix)'.dev-dependencies]
|
||||
nix = "0.20.0"
|
||||
|
||||
rust-users = { version="0.10", package="users" }
|
||||
unix_socket = "0.5.0"
|
||||
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "base32"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -23,3 +23,7 @@ uu_base32 = { version=">=0.0.6", package="uu_base32", path="../base32"}
|
|||
[[bin]]
|
||||
name = "base64"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "basename"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -23,3 +23,7 @@ uu_base32 = { version=">=0.0.6", package="uu_base32", path="../base32"}
|
|||
[[bin]]
|
||||
name = "basenc"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -23,3 +23,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "cksum"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -23,3 +23,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "comm"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -45,3 +45,7 @@ path = "src/main.rs"
|
|||
[features]
|
||||
feat_selinux = ["selinux"]
|
||||
feat_acl = ["exacl"]
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -18,10 +18,13 @@ path = "src/csplit.rs"
|
|||
clap = { version = "2.33", features = ["wrap_help"] }
|
||||
thiserror = "1.0"
|
||||
regex = "1.0.0"
|
||||
glob = "0.3"
|
||||
uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["entries", "fs"] }
|
||||
uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" }
|
||||
|
||||
[[bin]]
|
||||
name = "csplit"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -25,3 +25,7 @@ atty = "0.2"
|
|||
[[bin]]
|
||||
name = "cut"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -29,3 +29,7 @@ winapi = { version = "0.3", features = ["minwinbase", "sysinfoapi", "minwindef"]
|
|||
[[bin]]
|
||||
name = "date"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -31,3 +31,7 @@ signal-hook = "0.3.9"
|
|||
[[bin]]
|
||||
name = "dd"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -23,3 +23,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "dircolors"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -23,3 +23,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "expand"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -26,3 +26,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "expr"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -34,3 +34,7 @@ path = "src/main.rs"
|
|||
|
||||
[lib]
|
||||
path = "src/cli.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -24,3 +24,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "fmt"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "fold"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -33,3 +33,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "hashsum"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "head"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -10,18 +10,13 @@
|
|||
#[macro_use]
|
||||
extern crate uucore;
|
||||
|
||||
use clap::{crate_version, App, Arg, ArgMatches};
|
||||
use std::collections::hash_set::HashSet;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::str;
|
||||
#[cfg(windows)]
|
||||
use uucore::error::UUsageError;
|
||||
use uucore::error::{UResult, USimpleError};
|
||||
|
||||
#[cfg(windows)]
|
||||
use winapi::shared::minwindef::MAKEWORD;
|
||||
#[cfg(windows)]
|
||||
use winapi::um::winsock2::{WSACleanup, WSAStartup};
|
||||
use clap::{crate_version, App, Arg, ArgMatches};
|
||||
|
||||
use uucore::error::{FromIo, UResult};
|
||||
|
||||
static ABOUT: &str = "Display or set the system's host name.";
|
||||
|
||||
|
@ -31,45 +26,52 @@ static OPT_FQDN: &str = "fqdn";
|
|||
static OPT_SHORT: &str = "short";
|
||||
static OPT_HOST: &str = "host";
|
||||
|
||||
#[uucore_procs::gen_uumain]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
#![allow(clippy::let_and_return)]
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
#[allow(deprecated)]
|
||||
let mut data = std::mem::uninitialized();
|
||||
if WSAStartup(MAKEWORD(2, 2), &mut data as *mut _) != 0 {
|
||||
return Err(UUsageError::new(
|
||||
1,
|
||||
"Failed to start Winsock 2.2".to_string(),
|
||||
));
|
||||
#[cfg(windows)]
|
||||
mod wsa {
|
||||
use std::io;
|
||||
|
||||
use winapi::shared::minwindef::MAKEWORD;
|
||||
use winapi::um::winsock2::{WSACleanup, WSAStartup, WSADATA};
|
||||
|
||||
pub(super) struct WsaHandle(());
|
||||
|
||||
pub(super) fn start() -> io::Result<WsaHandle> {
|
||||
let err = unsafe {
|
||||
let mut data = std::mem::MaybeUninit::<WSADATA>::uninit();
|
||||
WSAStartup(MAKEWORD(2, 2), data.as_mut_ptr())
|
||||
};
|
||||
if err != 0 {
|
||||
Err(io::Error::from_raw_os_error(err))
|
||||
} else {
|
||||
Ok(WsaHandle(()))
|
||||
}
|
||||
}
|
||||
let result = execute(args);
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
WSACleanup();
|
||||
|
||||
impl Drop for WsaHandle {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
// This possibly returns an error but we can't handle it
|
||||
let _err = WSACleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn usage() -> String {
|
||||
format!("{0} [OPTION]... [HOSTNAME]", uucore::execution_phrase())
|
||||
}
|
||||
|
||||
fn execute(args: impl uucore::Args) -> UResult<()> {
|
||||
#[uucore_procs::gen_uumain]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let usage = usage();
|
||||
let matches = uu_app().usage(&usage[..]).get_matches_from(args);
|
||||
|
||||
match matches.value_of(OPT_HOST) {
|
||||
#[cfg(windows)]
|
||||
let _handle = wsa::start().map_err_context(|| "failed to start Winsock".to_owned())?;
|
||||
|
||||
match matches.value_of_os(OPT_HOST) {
|
||||
None => display_hostname(&matches),
|
||||
Some(host) => {
|
||||
if let Err(err) = hostname::set(host) {
|
||||
return Err(USimpleError::new(1, format!("{}", err)));
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Some(host) => hostname::set(host).map_err_context(|| "failed to set hostname".to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,64 +83,68 @@ pub fn uu_app() -> App<'static, 'static> {
|
|||
Arg::with_name(OPT_DOMAIN)
|
||||
.short("d")
|
||||
.long("domain")
|
||||
.overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT])
|
||||
.help("Display the name of the DNS domain if possible"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(OPT_IP_ADDRESS)
|
||||
.short("i")
|
||||
.long("ip-address")
|
||||
.overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT])
|
||||
.help("Display the network address(es) of the host"),
|
||||
)
|
||||
// TODO: support --long
|
||||
.arg(
|
||||
Arg::with_name(OPT_FQDN)
|
||||
.short("f")
|
||||
.long("fqdn")
|
||||
.overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT])
|
||||
.help("Display the FQDN (Fully Qualified Domain Name) (default)"),
|
||||
)
|
||||
.arg(Arg::with_name(OPT_SHORT).short("s").long("short").help(
|
||||
"Display the short hostname (the portion before the first dot) if \
|
||||
possible",
|
||||
))
|
||||
.arg(
|
||||
Arg::with_name(OPT_SHORT)
|
||||
.short("s")
|
||||
.long("short")
|
||||
.overrides_with_all(&[OPT_DOMAIN, OPT_IP_ADDRESS, OPT_FQDN, OPT_SHORT])
|
||||
.help("Display the short hostname (the portion before the first dot) if possible"),
|
||||
)
|
||||
.arg(Arg::with_name(OPT_HOST))
|
||||
}
|
||||
|
||||
fn display_hostname(matches: &ArgMatches) -> UResult<()> {
|
||||
let hostname = hostname::get().unwrap().into_string().unwrap();
|
||||
let hostname = hostname::get()
|
||||
.map_err_context(|| "failed to get hostname".to_owned())?
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
|
||||
if matches.is_present(OPT_IP_ADDRESS) {
|
||||
// XXX: to_socket_addrs needs hostname:port so append a dummy port and remove it later.
|
||||
// This was originally supposed to use std::net::lookup_host, but that seems to be
|
||||
// deprecated. Perhaps we should use the dns-lookup crate?
|
||||
let hostname = hostname + ":1";
|
||||
match hostname.to_socket_addrs() {
|
||||
Ok(addresses) => {
|
||||
let mut hashset = HashSet::new();
|
||||
let mut output = String::new();
|
||||
for addr in addresses {
|
||||
// XXX: not sure why this is necessary...
|
||||
if !hashset.contains(&addr) {
|
||||
let mut ip = format!("{}", addr);
|
||||
if ip.ends_with(":1") {
|
||||
let len = ip.len();
|
||||
ip.truncate(len - 2);
|
||||
}
|
||||
output.push_str(&ip);
|
||||
output.push(' ');
|
||||
hashset.insert(addr);
|
||||
}
|
||||
let addresses = hostname
|
||||
.to_socket_addrs()
|
||||
.map_err_context(|| "failed to resolve socket addresses".to_owned())?;
|
||||
let mut hashset = HashSet::new();
|
||||
let mut output = String::new();
|
||||
for addr in addresses {
|
||||
// XXX: not sure why this is necessary...
|
||||
if !hashset.contains(&addr) {
|
||||
let mut ip = addr.to_string();
|
||||
if ip.ends_with(":1") {
|
||||
let len = ip.len();
|
||||
ip.truncate(len - 2);
|
||||
}
|
||||
let len = output.len();
|
||||
if len > 0 {
|
||||
println!("{}", &output[0..len - 1]);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(f) => {
|
||||
return Err(USimpleError::new(1, format!("{}", f)));
|
||||
output.push_str(&ip);
|
||||
output.push(' ');
|
||||
hashset.insert(addr);
|
||||
}
|
||||
}
|
||||
let len = output.len();
|
||||
if len > 0 {
|
||||
println!("{}", &output[0..len - 1]);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
if matches.is_present(OPT_SHORT) || matches.is_present(OPT_DOMAIN) {
|
||||
let mut it = hostname.char_indices().filter(|&ci| ci.1 == '.');
|
||||
|
|
|
@ -490,11 +490,10 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR
|
|||
return Err(InstallError::TargetDirIsntDir(target_dir.to_path_buf()).into());
|
||||
}
|
||||
for sourcepath in files.iter() {
|
||||
if !sourcepath.exists() {
|
||||
let err = UIoError::new(
|
||||
std::io::ErrorKind::NotFound,
|
||||
format!("cannot stat {}", sourcepath.quote()),
|
||||
);
|
||||
if let Err(err) = sourcepath
|
||||
.metadata()
|
||||
.map_err_context(|| format!("cannot stat {}", sourcepath.quote()))
|
||||
{
|
||||
show!(err);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "join"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -23,3 +23,7 @@ clap = { version = "2.33", features = ["wrap_help"] }
|
|||
[[bin]]
|
||||
name = "link"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -15,7 +15,6 @@ edition = "2018"
|
|||
path = "src/ls.rs"
|
||||
|
||||
[dependencies]
|
||||
locale = "0.2.2"
|
||||
chrono = "0.4.19"
|
||||
clap = { version = "2.33", features = ["wrap_help"] }
|
||||
unicode-width = "0.1.8"
|
||||
|
@ -39,3 +38,7 @@ path = "src/main.rs"
|
|||
|
||||
[features]
|
||||
feat_selinux = ["selinux"]
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -42,7 +42,7 @@ use std::{
|
|||
use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
|
||||
use uucore::{
|
||||
display::Quotable,
|
||||
error::{set_exit_code, FromIo, UError, UResult},
|
||||
error::{set_exit_code, UError, UResult},
|
||||
};
|
||||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
@ -1333,8 +1333,13 @@ fn list(locs: Vec<&Path>, config: Config) -> UResult<()> {
|
|||
let path_data = PathData::new(p, None, None, &config, true);
|
||||
|
||||
if path_data.md().is_none() {
|
||||
show!(std::io::ErrorKind::NotFound
|
||||
.map_err_context(|| format!("cannot access {}", path_data.p_buf.quote())));
|
||||
// FIXME: Would be nice to use the actual error instead of hardcoding it
|
||||
// Presumably other errors can happen too?
|
||||
show_error!(
|
||||
"cannot access {}: No such file or directory",
|
||||
path_data.p_buf.quote()
|
||||
);
|
||||
set_exit_code(1);
|
||||
// We found an error, no need to continue the execution
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -33,3 +33,7 @@ nix = "0.19"
|
|||
[[bin]]
|
||||
name = "more"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -23,3 +23,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "mv"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -17,7 +17,7 @@ path = "src/nice.rs"
|
|||
[dependencies]
|
||||
clap = { version = "2.33", features = ["wrap_help"] }
|
||||
libc = "0.2.42"
|
||||
nix = { version="<=0.13" }
|
||||
nix = "0.20"
|
||||
uucore = { version=">=0.0.9", package="uucore", path="../../uucore" }
|
||||
uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" }
|
||||
|
||||
|
|
|
@ -27,3 +27,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "nl"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "numfmt"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -25,3 +25,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "od"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "paste"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -19,8 +19,6 @@ clap = { version = "2.33", features = ["wrap_help"] }
|
|||
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["entries"] }
|
||||
uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" }
|
||||
getopts = "0.2.21"
|
||||
time = "0.1.41"
|
||||
# A higher version would cause a conflict with time
|
||||
chrono = "0.4.19"
|
||||
quick-error = "2.0.1"
|
||||
itertools = "0.10"
|
||||
|
@ -29,3 +27,7 @@ regex = "1.0"
|
|||
[[bin]]
|
||||
name = "pr"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "printenv"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -26,3 +26,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "printf"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -27,3 +27,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "ptx"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -23,3 +23,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "readlink"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "realpath"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "relpath"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -18,12 +18,16 @@ path = "src/rm.rs"
|
|||
clap = { version = "2.33", features = ["wrap_help"] }
|
||||
walkdir = "2.2"
|
||||
remove_dir_all = "0.5.1"
|
||||
winapi = { version="0.3", features=[] }
|
||||
|
||||
uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["fs"] }
|
||||
uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version="0.3", features=[] }
|
||||
|
||||
[[bin]]
|
||||
name = "rm"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -24,3 +24,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "seq"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -12,7 +12,7 @@ use num_traits::One;
|
|||
use num_traits::Zero;
|
||||
use num_traits::{Num, ToPrimitive};
|
||||
use std::cmp;
|
||||
use std::io::{stdout, Write};
|
||||
use std::io::{stdout, ErrorKind, Write};
|
||||
use std::str::FromStr;
|
||||
use uucore::display::Quotable;
|
||||
|
||||
|
@ -99,6 +99,7 @@ impl Number {
|
|||
impl FromStr for Number {
|
||||
type Err = String;
|
||||
fn from_str(mut s: &str) -> Result<Self, Self::Err> {
|
||||
s = s.trim_start();
|
||||
if s.starts_with('+') {
|
||||
s = &s[1..];
|
||||
}
|
||||
|
@ -192,7 +193,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
.num_digits()
|
||||
.max(increment.num_digits())
|
||||
.max(last.num_digits());
|
||||
match (first, last, increment) {
|
||||
let result = match (first, last, increment) {
|
||||
(Number::MinusZero, Number::BigInt(last), Number::BigInt(increment)) => print_seq_integers(
|
||||
(BigInt::zero(), increment, last),
|
||||
options.separator,
|
||||
|
@ -219,8 +220,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
options.widths,
|
||||
padding,
|
||||
),
|
||||
};
|
||||
match result {
|
||||
Ok(_) => 0,
|
||||
Err(err) if err.kind() == ErrorKind::BrokenPipe => 0,
|
||||
Err(_) => 1,
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
pub fn uu_app() -> App<'static, 'static> {
|
||||
|
@ -276,30 +281,35 @@ fn print_seq(
|
|||
terminator: String,
|
||||
pad: bool,
|
||||
padding: usize,
|
||||
) {
|
||||
) -> std::io::Result<()> {
|
||||
let stdout = stdout();
|
||||
let mut stdout = stdout.lock();
|
||||
let (first, increment, last) = range;
|
||||
let mut i = 0isize;
|
||||
let mut value = first + i as f64 * increment;
|
||||
let mut is_first_iteration = true;
|
||||
while !done_printing(&value, &increment, &last) {
|
||||
if !is_first_iteration {
|
||||
write!(stdout, "{}", separator)?;
|
||||
}
|
||||
is_first_iteration = false;
|
||||
let istr = format!("{:.*}", largest_dec, value);
|
||||
let ilen = istr.len();
|
||||
let before_dec = istr.find('.').unwrap_or(ilen);
|
||||
if pad && before_dec < padding {
|
||||
for _ in 0..(padding - before_dec) {
|
||||
print!("0");
|
||||
write!(stdout, "0")?;
|
||||
}
|
||||
}
|
||||
print!("{}", istr);
|
||||
write!(stdout, "{}", istr)?;
|
||||
i += 1;
|
||||
value = first + i as f64 * increment;
|
||||
if !done_printing(&value, &increment, &last) {
|
||||
print!("{}", separator);
|
||||
}
|
||||
}
|
||||
if (first >= last && increment < 0f64) || (first <= last && increment > 0f64) {
|
||||
print!("{}", terminator);
|
||||
if !is_first_iteration {
|
||||
write!(stdout, "{}", terminator)?;
|
||||
}
|
||||
crash_if_err!(1, stdout().flush());
|
||||
stdout.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Print an integer sequence.
|
||||
|
@ -323,31 +333,34 @@ fn print_seq_integers(
|
|||
pad: bool,
|
||||
padding: usize,
|
||||
is_first_minus_zero: bool,
|
||||
) {
|
||||
) -> std::io::Result<()> {
|
||||
let stdout = stdout();
|
||||
let mut stdout = stdout.lock();
|
||||
let (first, increment, last) = range;
|
||||
let mut value = first;
|
||||
let mut is_first_iteration = true;
|
||||
while !done_printing(&value, &increment, &last) {
|
||||
if !is_first_iteration {
|
||||
print!("{}", separator);
|
||||
write!(stdout, "{}", separator)?;
|
||||
}
|
||||
let mut width = padding;
|
||||
if is_first_iteration && is_first_minus_zero {
|
||||
print!("-");
|
||||
write!(stdout, "-")?;
|
||||
width -= 1;
|
||||
}
|
||||
is_first_iteration = false;
|
||||
if pad {
|
||||
print!("{number:>0width$}", number = value, width = width);
|
||||
write!(stdout, "{number:>0width$}", number = value, width = width)?;
|
||||
} else {
|
||||
print!("{}", value);
|
||||
write!(stdout, "{}", value)?;
|
||||
}
|
||||
value += &increment;
|
||||
}
|
||||
|
||||
if !is_first_iteration {
|
||||
print!("{}", terminator);
|
||||
write!(stdout, "{}", terminator)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -16,13 +16,15 @@ path = "src/shred.rs"
|
|||
|
||||
[dependencies]
|
||||
clap = { version = "2.33", features = ["wrap_help"] }
|
||||
filetime = "0.2.1"
|
||||
libc = "0.2.42"
|
||||
rand = "0.7"
|
||||
time = "0.1.40"
|
||||
uucore = { version=">=0.0.9", package="uucore", path="../../uucore" }
|
||||
uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" }
|
||||
|
||||
[[bin]]
|
||||
name = "shred"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -23,3 +23,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "shuf"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "split"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "sum"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -16,6 +16,7 @@ path = "src/tac.rs"
|
|||
|
||||
[dependencies]
|
||||
memchr = "2"
|
||||
regex = "1"
|
||||
clap = { version = "2.33", features = ["wrap_help"] }
|
||||
uucore = { version=">=0.0.9", package="uucore", path="../../uucore" }
|
||||
uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" }
|
||||
|
@ -23,3 +24,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "tac"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -69,7 +69,7 @@ pub fn uu_app() -> App<'static, 'static> {
|
|||
Arg::with_name(options::REGEX)
|
||||
.short("r")
|
||||
.long(options::REGEX)
|
||||
.help("interpret the sequence as a regular expression (NOT IMPLEMENTED)")
|
||||
.help("interpret the sequence as a regular expression")
|
||||
.takes_value(false),
|
||||
)
|
||||
.arg(
|
||||
|
@ -82,6 +82,82 @@ pub fn uu_app() -> App<'static, 'static> {
|
|||
.arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
|
||||
}
|
||||
|
||||
/// Print lines of a buffer in reverse, with line separator given as a regex.
|
||||
///
|
||||
/// `data` contains the bytes of the file.
|
||||
///
|
||||
/// `pattern` is the regular expression given as a
|
||||
/// [`regex::bytes::Regex`] (not a [`regex::Regex`], since the input is
|
||||
/// given as a slice of bytes). If `before` is `true`, then each match
|
||||
/// of this pattern in `data` is interpreted as the start of a line. If
|
||||
/// `before` is `false`, then each match of this pattern is interpreted
|
||||
/// as the end of a line.
|
||||
///
|
||||
/// This function writes each line in `data` to [`std::io::Stdout`] in
|
||||
/// reverse.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If there is a problem writing to `stdout`, then this function
|
||||
/// returns [`std::io::Error`].
|
||||
fn buffer_tac_regex(
|
||||
data: &[u8],
|
||||
pattern: regex::bytes::Regex,
|
||||
before: bool,
|
||||
) -> std::io::Result<()> {
|
||||
let mut out = stdout();
|
||||
|
||||
// The index of the line separator for the current line.
|
||||
//
|
||||
// As we scan through the `data` from right to left, we update this
|
||||
// variable each time we find a new line separator. We restrict our
|
||||
// regular expression search to only those bytes up to the line
|
||||
// separator.
|
||||
let mut this_line_end = data.len();
|
||||
|
||||
// The index of the start of the next line in the `data`.
|
||||
//
|
||||
// As we scan through the `data` from right to left, we update this
|
||||
// variable each time we find a new line.
|
||||
//
|
||||
// If `before` is `true`, then each line starts immediately before
|
||||
// the line separator. Otherwise, each line starts immediately after
|
||||
// the line separator.
|
||||
let mut following_line_start = data.len();
|
||||
|
||||
// Iterate over each byte in the buffer in reverse. When we find a
|
||||
// line separator, write the line to stdout.
|
||||
//
|
||||
// The `before` flag controls whether the line separator appears at
|
||||
// the end of the line (as in "abc\ndef\n") or at the beginning of
|
||||
// the line (as in "/abc/def").
|
||||
for i in (0..data.len()).rev() {
|
||||
// Determine if there is a match for `pattern` starting at index
|
||||
// `i` in `data`. Only search up to the line ending that was
|
||||
// found previously.
|
||||
if let Some(match_) = pattern.find_at(&data[..this_line_end], i) {
|
||||
// Record this index as the ending of the current line.
|
||||
this_line_end = i;
|
||||
|
||||
// The length of the match (that is, the line separator), in bytes.
|
||||
let slen = match_.end() - match_.start();
|
||||
|
||||
if before {
|
||||
out.write_all(&data[i..following_line_start])?;
|
||||
following_line_start = i;
|
||||
} else {
|
||||
out.write_all(&data[i + slen..following_line_start])?;
|
||||
following_line_start = i + slen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After the loop terminates, write whatever bytes are remaining at
|
||||
// the beginning of the buffer.
|
||||
out.write_all(&data[0..following_line_start])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write lines from `data` to stdout in reverse.
|
||||
///
|
||||
/// This function writes to [`stdout`] each line appearing in `data`,
|
||||
|
@ -132,7 +208,7 @@ fn buffer_tac(data: &[u8], before: bool, separator: &str) -> std::io::Result<()>
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn tac(filenames: Vec<String>, before: bool, _: bool, separator: &str) -> i32 {
|
||||
fn tac(filenames: Vec<String>, before: bool, regex: bool, separator: &str) -> i32 {
|
||||
let mut exit_code = 0;
|
||||
|
||||
for filename in &filenames {
|
||||
|
@ -168,9 +244,13 @@ fn tac(filenames: Vec<String>, before: bool, _: bool, separator: &str) -> i32 {
|
|||
exit_code = 1;
|
||||
continue;
|
||||
};
|
||||
|
||||
buffer_tac(&data, before, separator)
|
||||
.unwrap_or_else(|e| crash!(1, "failed to write to stdout: {}", e));
|
||||
if regex {
|
||||
let pattern = crash_if_err!(1, regex::bytes::Regex::new(separator));
|
||||
buffer_tac_regex(&data, pattern, before)
|
||||
} else {
|
||||
buffer_tac(&data, before, separator)
|
||||
}
|
||||
.unwrap_or_else(|e| crash!(1, "failed to write to stdout: {}", e));
|
||||
}
|
||||
exit_code
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ clap = { version = "2.33", features = ["wrap_help"] }
|
|||
libc = "0.2.42"
|
||||
uucore = { version=">=0.0.9", package="uucore", path="../../uucore", features=["ringbuffer"] }
|
||||
uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_procs" }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version="0.3", features=["fileapi", "handleapi", "processthreadsapi", "synchapi", "winbase"] }
|
||||
|
||||
[target.'cfg(target_os = "redox")'.dependencies]
|
||||
|
@ -31,3 +33,7 @@ libc = "0.2"
|
|||
[[bin]]
|
||||
name = "tail"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -24,3 +24,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "tee"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -26,3 +26,7 @@ redox_syscall = "0.2"
|
|||
[[bin]]
|
||||
name = "test"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -24,3 +24,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "tr"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "truncate"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -22,3 +22,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "tsort"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -23,3 +23,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "unexpand"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -24,3 +24,7 @@ uucore_procs = { version=">=0.0.6", package="uucore_procs", path="../../uucore_p
|
|||
[[bin]]
|
||||
name = "uniq"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -29,3 +29,7 @@ libc = "0.2"
|
|||
[[bin]]
|
||||
name = "wc"
|
||||
path = "src/main.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
# Necessary for "make all"
|
||||
normal = ["uucore_procs"]
|
||||
|
|
|
@ -24,13 +24,15 @@ wild = "2.0"
|
|||
# * optional
|
||||
thiserror = { version="1.0", optional=true }
|
||||
time = { version="<= 0.1.43", optional=true }
|
||||
walkdir = { version="2.3.2", optional=true }
|
||||
# * "problem" dependencies (pinned)
|
||||
data-encoding = { version="2.1", optional=true }
|
||||
data-encoding-macro = { version="0.1.12", optional=true }
|
||||
z85 = { version="3.0.3", optional=true }
|
||||
libc = { version="0.2.15", optional=true }
|
||||
once_cell = "1.8.0"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
walkdir = { version="2.3.2", optional=true }
|
||||
nix = { version="0.20", optional=true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -393,34 +393,56 @@ impl Display for UIoError {
|
|||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
use std::io::ErrorKind::*;
|
||||
|
||||
let message;
|
||||
let message = match self.inner.kind() {
|
||||
NotFound => "No such file or directory",
|
||||
PermissionDenied => "Permission denied",
|
||||
ConnectionRefused => "Connection refused",
|
||||
ConnectionReset => "Connection reset",
|
||||
ConnectionAborted => "Connection aborted",
|
||||
NotConnected => "Not connected",
|
||||
AddrInUse => "Address in use",
|
||||
AddrNotAvailable => "Address not available",
|
||||
BrokenPipe => "Broken pipe",
|
||||
AlreadyExists => "Already exists",
|
||||
WouldBlock => "Would block",
|
||||
InvalidInput => "Invalid input",
|
||||
InvalidData => "Invalid data",
|
||||
TimedOut => "Timed out",
|
||||
WriteZero => "Write zero",
|
||||
Interrupted => "Interrupted",
|
||||
UnexpectedEof => "Unexpected end of file",
|
||||
_ => {
|
||||
// TODO: using `strip_errno()` causes the error message
|
||||
// to not be capitalized. When the new error variants (https://github.com/rust-lang/rust/issues/86442)
|
||||
// are stabilized, we should add them to the match statement.
|
||||
message = strip_errno(&self.inner);
|
||||
&message
|
||||
let mut message;
|
||||
let message = if self.inner.raw_os_error().is_some() {
|
||||
// These are errors that come directly from the OS.
|
||||
// We want to normalize their messages across systems,
|
||||
// and we want to strip the "(os error X)" suffix.
|
||||
match self.inner.kind() {
|
||||
NotFound => "No such file or directory",
|
||||
PermissionDenied => "Permission denied",
|
||||
ConnectionRefused => "Connection refused",
|
||||
ConnectionReset => "Connection reset",
|
||||
ConnectionAborted => "Connection aborted",
|
||||
NotConnected => "Not connected",
|
||||
AddrInUse => "Address in use",
|
||||
AddrNotAvailable => "Address not available",
|
||||
BrokenPipe => "Broken pipe",
|
||||
AlreadyExists => "Already exists",
|
||||
WouldBlock => "Would block",
|
||||
InvalidInput => "Invalid input",
|
||||
InvalidData => "Invalid data",
|
||||
TimedOut => "Timed out",
|
||||
WriteZero => "Write zero",
|
||||
Interrupted => "Interrupted",
|
||||
UnexpectedEof => "Unexpected end of file",
|
||||
_ => {
|
||||
// TODO: When the new error variants
|
||||
// (https://github.com/rust-lang/rust/issues/86442)
|
||||
// are stabilized, we should add them to the match statement.
|
||||
message = strip_errno(&self.inner);
|
||||
capitalize(&mut message);
|
||||
&message
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// These messages don't need as much normalization, and the above
|
||||
// messages wouldn't always be a good substitute.
|
||||
// For example, ErrorKind::NotFound doesn't necessarily mean it was
|
||||
// a file that was not found.
|
||||
// There are also errors with entirely custom messages.
|
||||
message = self.inner.to_string();
|
||||
capitalize(&mut message);
|
||||
&message
|
||||
};
|
||||
write!(f, "{}: {}", self.context, message,)
|
||||
write!(f, "{}: {}", self.context, message)
|
||||
}
|
||||
}
|
||||
|
||||
/// Capitalize the first character of an ASCII string.
|
||||
fn capitalize(text: &mut str) {
|
||||
if let Some(first) = text.get_mut(..1) {
|
||||
first.make_ascii_uppercase();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,7 +450,7 @@ impl Display for UIoError {
|
|||
pub fn strip_errno(err: &std::io::Error) -> String {
|
||||
let mut msg = err.to_string();
|
||||
if let Some(pos) = msg.find(" (os error ") {
|
||||
msg.drain(pos..);
|
||||
msg.truncate(pos);
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
|
|
@ -1,17 +1,42 @@
|
|||
//! Custom panic hooks that allow silencing certain types of errors.
|
||||
//!
|
||||
//! Use the [`mute_sigpipe_panic`] function to silence panics caused by
|
||||
//! broken pipe errors. This can happen when a process is still
|
||||
//! producing data when the consuming process terminates and closes the
|
||||
//! pipe. For example,
|
||||
//!
|
||||
//! ```sh
|
||||
//! $ seq inf | head -n 1
|
||||
//! ```
|
||||
//!
|
||||
use std::panic;
|
||||
use std::panic::PanicInfo;
|
||||
|
||||
//## SIGPIPE handling background/discussions ...
|
||||
//* `uutils` ~ <https://github.com/uutils/coreutils/issues/374> , <https://github.com/uutils/coreutils/pull/1106>
|
||||
//* rust and `rg` ~ <https://github.com/rust-lang/rust/issues/62569> , <https://github.com/BurntSushi/ripgrep/issues/200> , <https://github.com/crev-dev/cargo-crev/issues/287>
|
||||
/// Decide whether a panic was caused by a broken pipe (SIGPIPE) error.
|
||||
fn is_broken_pipe(info: &PanicInfo) -> bool {
|
||||
if let Some(res) = info.payload().downcast_ref::<String>() {
|
||||
if res.contains("BrokenPipe") || res.contains("Broken pipe") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Terminate without error on panics that occur due to broken pipe errors.
|
||||
///
|
||||
/// For background discussions on `SIGPIPE` handling, see
|
||||
///
|
||||
/// * https://github.com/uutils/coreutils/issues/374
|
||||
/// * https://github.com/uutils/coreutils/pull/1106
|
||||
/// * https://github.com/rust-lang/rust/issues/62569
|
||||
/// * https://github.com/BurntSushi/ripgrep/issues/200
|
||||
/// * https://github.com/crev-dev/cargo-crev/issues/287
|
||||
///
|
||||
pub fn mute_sigpipe_panic() {
|
||||
let hook = panic::take_hook();
|
||||
panic::set_hook(Box::new(move |info| {
|
||||
if let Some(res) = info.payload().downcast_ref::<String>() {
|
||||
if res.contains("BrokenPipe") {
|
||||
return;
|
||||
}
|
||||
if !is_broken_pipe(info) {
|
||||
hook(info)
|
||||
}
|
||||
hook(info)
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::os::unix::fs;
|
|||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::symlink as symlink_file;
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(target_os = "freebsd")))]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::fs::symlink_file;
|
||||
|
|
|
@ -373,6 +373,7 @@ fn test_ls_long_format() {
|
|||
/// This test does not really test anything provided by `-l` but the file names and symlinks.
|
||||
#[cfg(all(feature = "ln", feature = "mkdir", feature = "touch"))]
|
||||
#[test]
|
||||
#[cfg(all(feature = "ln", feature = "mkdir", feature = "touch"))]
|
||||
fn test_ls_long_symlink_color() {
|
||||
// If you break this test after breaking mkdir, touch, or ln, do not be alarmed!
|
||||
// This test is made for ls, but it attempts to run those utils in the process.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::common::util::*;
|
||||
use std::io::Read;
|
||||
|
||||
#[test]
|
||||
fn test_rejects_nan() {
|
||||
|
@ -176,3 +177,50 @@ fn test_width_negative_zero() {
|
|||
.stdout_is("-0\n01\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
// TODO This is duplicated from `test_yes.rs`; refactor them.
|
||||
/// Run `seq`, capture some of the output, close the pipe, and verify it.
|
||||
fn run(args: &[&str], expected: &[u8]) {
|
||||
let mut cmd = new_ucmd!();
|
||||
let mut child = cmd.args(args).run_no_wait();
|
||||
let mut stdout = child.stdout.take().unwrap();
|
||||
let mut buf = vec![0; expected.len()];
|
||||
stdout.read_exact(&mut buf).unwrap();
|
||||
drop(stdout);
|
||||
assert!(child.wait().unwrap().success());
|
||||
assert_eq!(buf.as_slice(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_neg_inf() {
|
||||
run(&["--", "-inf", "0"], b"-inf\n-inf\n-inf\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inf() {
|
||||
run(&["inf"], b"1\n2\n3\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ignore_leading_whitespace() {
|
||||
new_ucmd!()
|
||||
.arg(" 1")
|
||||
.succeeds()
|
||||
.stdout_is("1\n")
|
||||
.no_stderr();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trailing_whitespace_error() {
|
||||
// In some locales, the GNU error message has curly quotes (‘)
|
||||
// instead of straight quotes ('). We just test the straight single
|
||||
// quotes.
|
||||
new_ucmd!()
|
||||
.arg("1 ")
|
||||
.fails()
|
||||
.no_stdout()
|
||||
.stderr_contains("seq: invalid floating point argument: '1 '")
|
||||
// FIXME The second line of the error message is "Try 'seq
|
||||
// --help' for more information."
|
||||
.stderr_contains("for more information.");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// spell-checker:ignore axxbxx bxxaxx axxx axxxx xxaxx xxax xxxxa
|
||||
// spell-checker:ignore axxbxx bxxaxx axxx axxxx xxaxx xxax xxxxa axyz zyax zyxa
|
||||
use crate::common::util::*;
|
||||
|
||||
#[test]
|
||||
|
@ -205,3 +205,67 @@ fn test_null_separator() {
|
|||
.succeeds()
|
||||
.stdout_is("b\0a\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_regex() {
|
||||
new_ucmd!()
|
||||
.args(&["-r", "-s", "[xyz]+"])
|
||||
.pipe_in("axyz")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is("zyax");
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["-r", "-s", ":+"])
|
||||
.pipe_in("a:b::c:::d::::")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is(":::d:::c::b:a:");
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["-r", "-s", r"[\+]+[-]+[\+]+"])
|
||||
// line 0 1 2
|
||||
// |--||-----||--------|
|
||||
.pipe_in("a+-+b++--++c+d-e+---+")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
// line 2 1 0
|
||||
// |--------||-----||--|
|
||||
.stdout_is("c+d-e+---+b++--++a+-+");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_regex_before() {
|
||||
new_ucmd!()
|
||||
.args(&["-b", "-r", "-s", "[xyz]+"])
|
||||
.pipe_in("axyz")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is("zyxa");
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["-b", "-r", "-s", ":+"])
|
||||
.pipe_in(":a::b:::c::::d")
|
||||
.succeeds()
|
||||
.stdout_is(":d::::c:::b::a");
|
||||
|
||||
// Because `tac` searches for matches of the regular expression from
|
||||
// right to left, the second to last line is
|
||||
//
|
||||
// +--++b
|
||||
//
|
||||
// not
|
||||
//
|
||||
// ++--++b
|
||||
//
|
||||
new_ucmd!()
|
||||
.args(&["-b", "-r", "-s", r"[\+]+[-]+[\+]+"])
|
||||
// line 0 1 2
|
||||
// |---||----||--------|
|
||||
.pipe_in("+-+a++--++b+---+c+d-e")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
// line 2 1 0
|
||||
// |--------||----||---|
|
||||
.stdout_is("+---+c+d-e+--++b+-+a+");
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// * For the full copyright and license information, please view the LICENSE
|
||||
// * file that was distributed with this source code.
|
||||
|
||||
//spell-checker: ignore (linux) rlimit prlimit Rlim coreutil
|
||||
//spell-checker: ignore (linux) rlimit prlimit Rlim coreutil ggroups
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
@ -1081,7 +1081,14 @@ pub fn host_name_for(util_name: &str) -> Cow<str> {
|
|||
// In some environments, e.g. macOS/freebsd, the GNU coreutils are prefixed with "g"
|
||||
// to not interfere with the BSD counterparts already in `$PATH`.
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
return format!("g{}", util_name).into();
|
||||
{
|
||||
// make call to `host_name_for` idempotent
|
||||
if util_name.starts_with('g') && util_name != "groups" {
|
||||
return util_name.into();
|
||||
} else {
|
||||
return format!("g{}", util_name).into();
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
return util_name.into();
|
||||
}
|
||||
|
@ -1195,8 +1202,8 @@ pub fn check_coreutil_version(
|
|||
///```
|
||||
#[cfg(unix)]
|
||||
pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result<CmdResult, String> {
|
||||
println!("{}", check_coreutil_version(&ts.util_name, VERSION_MIN)?);
|
||||
let util_name = &host_name_for(&ts.util_name);
|
||||
println!("{}", check_coreutil_version(util_name, VERSION_MIN)?);
|
||||
|
||||
let result = ts
|
||||
.cmd_keepenv(util_name.as_ref())
|
||||
|
@ -1493,4 +1500,25 @@ mod tests {
|
|||
let ts = TestScenario::new("no test name");
|
||||
assert!(expected_result(&ts, &[]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(unix)]
|
||||
fn test_host_name_for() {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
std::assert_eq!(host_name_for("id"), "id");
|
||||
std::assert_eq!(host_name_for("groups"), "groups");
|
||||
std::assert_eq!(host_name_for("who"), "who");
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
// spell-checker:ignore (strings) ggroups gwho
|
||||
std::assert_eq!(host_name_for("id"), "gid");
|
||||
std::assert_eq!(host_name_for("groups"), "ggroups");
|
||||
std::assert_eq!(host_name_for("who"), "gwho");
|
||||
std::assert_eq!(host_name_for("gid"), "gid");
|
||||
std::assert_eq!(host_name_for("ggroups"), "ggroups");
|
||||
std::assert_eq!(host_name_for("gwho"), "gwho");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue