uv/crates/uv-cache-info/src/timestamp.rs

53 lines
1.8 KiB
Rust

use serde::{Deserialize, Serialize};
use std::path::Path;
/// A timestamp used to measure changes to a file.
///
/// On Unix, this uses `ctime` as a conservative approach. `ctime` should detect all
/// modifications, including some that we don't care about, like hardlink modifications.
/// On other platforms, it uses `mtime`.
///
/// See: <https://github.com/restic/restic/issues/2179>
/// See: <https://apenwarr.ca/log/20181113>
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
pub struct Timestamp(std::time::SystemTime);
impl Timestamp {
/// Return the [`Timestamp`] for the given path.
pub fn from_path(path: impl AsRef<Path>) -> std::io::Result<Self> {
let metadata = fs_err::metadata(path.as_ref())?;
Ok(Self::from_metadata(&metadata))
}
/// Return the [`Timestamp`] for the given metadata.
pub fn from_metadata(metadata: &std::fs::Metadata) -> Self {
#[cfg(unix)]
{
use std::os::unix::fs::MetadataExt;
let ctime = u64::try_from(metadata.ctime()).expect("ctime to be representable as u64");
let ctime_nsec = u32::try_from(metadata.ctime_nsec())
.expect("ctime_nsec to be representable as u32");
let duration = std::time::Duration::new(ctime, ctime_nsec);
Self(std::time::UNIX_EPOCH + duration)
}
#[cfg(not(unix))]
{
let modified = metadata.modified().expect("modified time to be available");
Self(modified)
}
}
/// Return the current [`Timestamp`].
pub fn now() -> Self {
Self(std::time::SystemTime::now())
}
}
impl From<std::time::SystemTime> for Timestamp {
fn from(system_time: std::time::SystemTime) -> Self {
Self(system_time)
}
}