mirror of
https://github.com/uutils/coreutils
synced 2024-10-07 00:19:14 +00:00
stat
: use chrono instead of time in fsext (#5934)
* stat: use chrono instead of time in fsext This removes the dependency of `fsext` on `time` and it cleans up the code. * stat: use chrono instead of time in fsext This removes the dependency of `fsext` on `time` and it cleans up the code. * stat: fix two errors from clippy & spell-checker * stat: move fn to fix clippy error * stat: print - if birth time unknown * uucore/fsext: fix "unused import" error on Windows --------- Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com>
This commit is contained in:
parent
33785c93a3
commit
177ac7ea28
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2909,6 +2909,7 @@ dependencies = [
|
|||
name = "uu_stat"
|
||||
version = "0.0.24"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"uucore",
|
||||
]
|
||||
|
|
|
@ -17,6 +17,7 @@ path = "src/stat.rs"
|
|||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["entries", "libc", "fs", "fsext"] }
|
||||
chrono = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "stat"
|
||||
|
|
|
@ -2,19 +2,19 @@
|
|||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
// spell-checker:ignore datetime
|
||||
|
||||
use clap::builder::ValueParser;
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{FromIo, UResult, USimpleError};
|
||||
use uucore::fs::display_permissions;
|
||||
use uucore::fsext::{
|
||||
pretty_filetype, pretty_fstype, pretty_time, read_fs_list, statfs, BirthTime, FsMeta,
|
||||
};
|
||||
use uucore::fsext::{pretty_filetype, pretty_fstype, read_fs_list, statfs, BirthTime, FsMeta};
|
||||
use uucore::libc::mode_t;
|
||||
use uucore::{
|
||||
entries, format_usage, help_about, help_section, help_usage, show_error, show_warning,
|
||||
};
|
||||
|
||||
use chrono::{DateTime, Local};
|
||||
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
|
||||
use std::borrow::Cow;
|
||||
use std::convert::AsRef;
|
||||
|
@ -809,10 +809,14 @@ impl Stater {
|
|||
}
|
||||
|
||||
// time of file birth, human-readable; - if unknown
|
||||
'w' => OutputType::Str(meta.pretty_birth()),
|
||||
'w' => OutputType::Str(
|
||||
meta.birth()
|
||||
.map(|(sec, nsec)| pretty_time(sec as i64, nsec as i64))
|
||||
.unwrap_or(String::from("-")),
|
||||
),
|
||||
|
||||
// time of file birth, seconds since Epoch; 0 if unknown
|
||||
'W' => OutputType::Unsigned(meta.birth()),
|
||||
'W' => OutputType::Unsigned(meta.birth().unwrap_or_default().0),
|
||||
|
||||
// time of last access, human-readable
|
||||
'x' => OutputType::Str(pretty_time(
|
||||
|
@ -950,6 +954,16 @@ pub fn uu_app() -> Command {
|
|||
)
|
||||
}
|
||||
|
||||
const PRETTY_DATETIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S.%f %z";
|
||||
|
||||
fn pretty_time(sec: i64, nsec: i64) -> String {
|
||||
// Return the date in UTC
|
||||
let tm = chrono::DateTime::from_timestamp(sec, nsec as u32).unwrap_or_default();
|
||||
let tm: DateTime<Local> = tm.into();
|
||||
|
||||
tm.format(PRETTY_DATETIME_FORMAT).to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{group_num, Flags, ScanUtil, Stater, Token};
|
||||
|
|
|
@ -77,7 +77,7 @@ colors = []
|
|||
encoding = ["data-encoding", "data-encoding-macro", "z85", "thiserror"]
|
||||
entries = ["libc"]
|
||||
fs = ["dunce", "libc", "winapi-util", "windows-sys"]
|
||||
fsext = ["libc", "time", "windows-sys"]
|
||||
fsext = ["libc", "windows-sys"]
|
||||
fsxattr = ["xattr"]
|
||||
lines = []
|
||||
format = ["itertools", "quoting-style"]
|
||||
|
|
|
@ -7,9 +7,6 @@
|
|||
|
||||
// spell-checker:ignore DATETIME getmntinfo subsecond (arch) bitrig ; (fs) cifs smbfs
|
||||
|
||||
use time::macros::format_description;
|
||||
use time::UtcOffset;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
const LINUX_MTAB: &str = "/etc/mtab";
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
|
@ -66,6 +63,7 @@ use libc::{
|
|||
mode_t, strerror, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
#[cfg(not(windows))]
|
||||
use std::convert::From;
|
||||
#[cfg(unix)]
|
||||
use std::ffi::CStr;
|
||||
|
@ -115,26 +113,16 @@ pub use libc::statfs as statfs_fn;
|
|||
pub use libc::statvfs as statfs_fn;
|
||||
|
||||
pub trait BirthTime {
|
||||
fn pretty_birth(&self) -> String;
|
||||
fn birth(&self) -> u64;
|
||||
fn birth(&self) -> Option<(u64, u32)>;
|
||||
}
|
||||
|
||||
use std::fs::Metadata;
|
||||
impl BirthTime for Metadata {
|
||||
fn pretty_birth(&self) -> String {
|
||||
fn birth(&self) -> Option<(u64, u32)> {
|
||||
self.created()
|
||||
.ok()
|
||||
.and_then(|t| t.duration_since(UNIX_EPOCH).ok())
|
||||
.map(|e| pretty_time(e.as_secs() as i64, i64::from(e.subsec_nanos())))
|
||||
.unwrap_or_else(|| "-".to_owned())
|
||||
}
|
||||
|
||||
fn birth(&self) -> u64 {
|
||||
self.created()
|
||||
.ok()
|
||||
.and_then(|t| t.duration_since(UNIX_EPOCH).ok())
|
||||
.map(|e| e.as_secs())
|
||||
.unwrap_or_default()
|
||||
.map(|e| (e.as_secs(), e.subsec_nanos()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -869,50 +857,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// match strftime "%Y-%m-%d %H:%M:%S.%f %z"
|
||||
const PRETTY_DATETIME_FORMAT: &[time::format_description::FormatItem] = format_description!(
|
||||
"\
|
||||
[year]-[month]-[day padding:zero] \
|
||||
[hour]:[minute]:[second].[subsecond digits:9] \
|
||||
[offset_hour sign:mandatory][offset_minute]"
|
||||
);
|
||||
|
||||
pub fn pretty_time(sec: i64, nsec: i64) -> String {
|
||||
// sec == seconds since UNIX_EPOCH
|
||||
// nsec == nanoseconds since (UNIX_EPOCH + sec)
|
||||
let ts_nanos: i128 = (sec * 1_000_000_000 + nsec).into();
|
||||
|
||||
// Return the date in UTC
|
||||
let tm = match time::OffsetDateTime::from_unix_timestamp_nanos(ts_nanos) {
|
||||
Ok(tm) => tm,
|
||||
Err(e) => {
|
||||
panic!("error: {e}");
|
||||
}
|
||||
};
|
||||
|
||||
// Get the offset to convert to local time
|
||||
// Because of DST (daylight saving), we get the local time back when
|
||||
// the date was set
|
||||
let local_offset = match UtcOffset::local_offset_at(tm) {
|
||||
Ok(lo) => lo,
|
||||
Err(_) if cfg!(target_os = "redox") => UtcOffset::UTC,
|
||||
Err(e) => {
|
||||
panic!("error: {e}");
|
||||
}
|
||||
};
|
||||
|
||||
// Include the conversion to local time
|
||||
let res = tm
|
||||
.to_offset(local_offset)
|
||||
.format(&PRETTY_DATETIME_FORMAT)
|
||||
.unwrap();
|
||||
if res.ends_with(" -0000") {
|
||||
res.replace(" -0000", " +0000")
|
||||
} else {
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn pretty_filetype<'a>(mode: mode_t, size: u64) -> &'a str {
|
||||
match mode & S_IFMT {
|
||||
|
|
Loading…
Reference in a new issue