tool: read build time from symlink

Read the build time from generation symlinks in /nix/var/nix/profiles
instead of from the underlying derivation. The derivation build time
will always be a UNIX epoch of 0 because of the `nix-build` sandbox,
which is useless for identifying when a generation was created.
This commit is contained in:
nikstur 2023-02-09 00:15:30 +01:00
parent 5f5b04a6f5
commit 06f921ead0
2 changed files with 16 additions and 7 deletions

View File

@ -7,6 +7,7 @@ use anyhow::{anyhow, Context, Result};
use bootspec::generation::Generation as BootspecGeneration; use bootspec::generation::Generation as BootspecGeneration;
use bootspec::BootJson; use bootspec::BootJson;
use bootspec::SpecialisationName; use bootspec::SpecialisationName;
use time::Date;
/// (Possibly) extended Bootspec. /// (Possibly) extended Bootspec.
/// ///
@ -29,6 +30,8 @@ pub struct ExtendedBootJson {
pub struct Generation { pub struct Generation {
/// Profile symlink index /// Profile symlink index
version: u64, version: u64,
/// Build time
build_time: Option<Date>,
/// Top-level specialisation name /// Top-level specialisation name
specialisation_name: Option<SpecialisationName>, specialisation_name: Option<SpecialisationName>,
/// Top-level extended boot specification /// Top-level extended boot specification
@ -49,6 +52,7 @@ impl Generation {
Ok(Self { Ok(Self {
version: link.version, version: link.version,
build_time: link.build_time,
specialisation_name: None, specialisation_name: None,
spec: ExtendedBootJson { bootspec }, spec: ExtendedBootJson { bootspec },
}) })
@ -57,6 +61,7 @@ impl Generation {
pub fn specialise(&self, name: &SpecialisationName, bootspec: &BootJson) -> Result<Self> { pub fn specialise(&self, name: &SpecialisationName, bootspec: &BootJson) -> Result<Self> {
Ok(Self { Ok(Self {
version: self.version, version: self.version,
build_time: self.build_time,
specialisation_name: Some(name.clone()), specialisation_name: Some(name.clone()),
spec: ExtendedBootJson { spec: ExtendedBootJson {
bootspec: bootspec.clone(), bootspec: bootspec.clone(),
@ -82,7 +87,10 @@ impl Generation {
.unwrap_or_else(|_| String::from("Unknown")); .unwrap_or_else(|_| String::from("Unknown"));
let kernel_version = let kernel_version =
read_kernel_version(toplevel).context("Failed to read kernel version.")?; read_kernel_version(toplevel).context("Failed to read kernel version.")?;
let build_time = read_build_time(toplevel).unwrap_or_else(|_| String::from("Unknown")); let build_time = self
.build_time
.map(|x| x.to_string())
.unwrap_or_else(|| String::from("Unknown"));
Ok(format!( Ok(format!(
"Generation {} NixOS {}, Linux Kernel {}, Built on {}", "Generation {} NixOS {}, Linux Kernel {}, Built on {}",
@ -116,10 +124,8 @@ fn read_kernel_version(toplevel: &Path) -> Result<String> {
Ok(String::from(file_name)) Ok(String::from(file_name))
} }
fn read_build_time(path: &Path) -> Result<String> { fn read_build_time(path: &Path) -> Result<Date> {
let build_time = time::OffsetDateTime::from_unix_timestamp(fs::metadata(path)?.mtime())? let build_time = time::OffsetDateTime::from_unix_timestamp(fs::metadata(path)?.mtime())?.date();
.date()
.to_string();
Ok(build_time) Ok(build_time)
} }
@ -131,6 +137,7 @@ fn read_build_time(path: &Path) -> Result<String> {
pub struct GenerationLink { pub struct GenerationLink {
pub version: u64, pub version: u64,
pub path: PathBuf, pub path: PathBuf,
pub build_time: Option<Date>,
} }
impl GenerationLink { impl GenerationLink {
@ -138,6 +145,7 @@ impl GenerationLink {
Ok(Self { Ok(Self {
version: parse_version(&path).context("Failed to parse version")?, version: parse_version(&path).context("Failed to parse version")?,
path: PathBuf::from(path.as_ref()), path: PathBuf::from(path.as_ref()),
build_time: read_build_time(path.as_ref()).ok(),
}) })
} }
} }

View File

@ -20,8 +20,6 @@ pub fn setup_generation_link(
version: u64, version: u64,
) -> Result<PathBuf> { ) -> Result<PathBuf> {
let toplevel = setup_toplevel(tmpdir).context("Failed to setup toplevel")?; let toplevel = setup_toplevel(tmpdir).context("Failed to setup toplevel")?;
// Explicitly set modification time so that snapshot test of os-release reliably works.
filetime::set_file_mtime(&toplevel, filetime::FileTime::zero())?;
let bootspec = json!({ let bootspec = json!({
"v1": { "v1": {
@ -55,6 +53,9 @@ pub fn setup_generation_link(
let mut file = fs::File::create(bootspec_path)?; let mut file = fs::File::create(bootspec_path)?;
file.write_all(&serde_json::to_vec(&bootspec)?)?; file.write_all(&serde_json::to_vec(&bootspec)?)?;
// Explicitly set modification time so that snapshot test of os-release reliably works.
// This has to happen after any modifications to the directory.
filetime::set_file_mtime(&generation_link_path, filetime::FileTime::zero())?;
Ok(generation_link_path) Ok(generation_link_path)
} }