mirror of https://github.com/astral-sh/uv
53 lines
1.8 KiB
Rust
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)
|
|
}
|
|
}
|