Skip to content

Commit

Permalink
Merge pull request #423 from HuijingHei/move-code-func
Browse files Browse the repository at this point in the history
util.rs: move some code to function to reuse
  • Loading branch information
cgwalters authored Jan 12, 2023
2 parents e8e25d0 + 14d9673 commit 7d95134
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 46 deletions.
48 changes: 3 additions & 45 deletions src/efi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/

use std::cell::RefCell;
use std::collections::{BTreeMap, BTreeSet};
use std::io::prelude::*;
use std::os::unix::io::AsRawFd;
use std::path::{Path, PathBuf};
Expand All @@ -14,8 +13,6 @@ use std::process::Command;
use anyhow::{bail, Context, Result};
use openat_ext::OpenatDirExt;

use chrono::prelude::*;

use crate::component::*;
use crate::filetree;
use crate::model::*;
Expand Down Expand Up @@ -267,56 +264,17 @@ impl Component for Efi {
Command::new("mv").args(&[&efisrc, &dest_efidir]).run()?;
}

let src_efidir = openat::Dir::open(&dest_efidir)?;
// Query the rpm database and list the package and build times for all the
// files in the EFI system partition. If any files are not owned it is considered
// and error condition.
let rpmout = {
let mut c = ostreeutil::rpm_cmd(sysroot_path);
c.args(&["-q", "--queryformat", "%{nevra},%{buildtime} ", "-f"]);
c.args(util::filenames(&src_efidir)?.drain().map(|mut f| {
f.insert_str(0, "/boot/efi/EFI/");
f
}));
c
}
.output()?;
let mut rpmout = util::rpm_query(sysroot_path, &dest_efidir)?;
let rpmout = rpmout.output()?;
if !rpmout.status.success() {
std::io::stderr().write_all(&rpmout.stderr)?;
bail!("Failed to invoke rpm -qf");
}
let pkgs = std::str::from_utf8(&rpmout.stdout)?
.split_whitespace()
.map(|s| -> Result<_> {
let parts: Vec<_> = s.splitn(2, ',').collect();
let name = parts[0];
if let Some(ts) = parts.get(1) {
let nt = NaiveDateTime::parse_from_str(ts, "%s")
.context("Failed to parse rpm buildtime")?;
Ok((name, DateTime::<Utc>::from_utc(nt, Utc)))
} else {
bail!("Failed to parse: {}", s);
}
})
.collect::<Result<BTreeMap<&str, DateTime<Utc>>>>()?;
if pkgs.is_empty() {
bail!("Failed to find any RPM packages matching files in source efidir");
}
let timestamps: BTreeSet<&DateTime<Utc>> = pkgs.values().collect();
// Unwrap safety: We validated pkgs has at least one value above
let largest_timestamp = timestamps.iter().last().unwrap();
let version = pkgs.keys().fold("".to_string(), |mut s, n| {
if !s.is_empty() {
s.push(',');
}
s.push_str(n);
s
});

let meta = ContentMetadata {
timestamp: **largest_timestamp,
version,
};
let meta = util::parse_rpm_metadata(rpmout.stdout)?;
write_update_metadata(sysroot_path, self, &meta)?;
Ok(meta)
}
Expand Down
63 changes: 62 additions & 1 deletion src/util.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
use std::collections::HashSet;

use anyhow::{bail, Result};
use anyhow::{bail, Context, Result};
use openat_ext::OpenatDirExt;

use std::path::Path;
use std::process::Command;

use crate::model::*;
use crate::ostreeutil;
use chrono::prelude::*;
use std::collections::{BTreeMap, BTreeSet};

pub(crate) trait CommandRunExt {
fn run(&mut self) -> Result<()>;
}
Expand Down Expand Up @@ -83,3 +88,59 @@ pub(crate) fn ensure_writable_mount<P: AsRef<Path>>(p: P) -> Result<()> {
}
Ok(())
}

/// Parse the output of `rpm -q`
pub(crate) fn parse_rpm_metadata(stdout: Vec<u8>) -> Result<ContentMetadata> {
let pkgs = std::str::from_utf8(&stdout)?
.split_whitespace()
.map(|s| -> Result<_> {
let parts: Vec<_> = s.splitn(2, ',').collect();
let name = parts[0];
if let Some(ts) = parts.get(1) {
let nt = NaiveDateTime::parse_from_str(ts, "%s")
.context("Failed to parse rpm buildtime")?;
Ok((name, DateTime::<Utc>::from_utc(nt, Utc)))
} else {
bail!("Failed to parse: {}", s);
}
})
.collect::<Result<BTreeMap<&str, DateTime<Utc>>>>()?;
if pkgs.is_empty() {
bail!("Failed to find any RPM packages matching files in source efidir");
}
let timestamps: BTreeSet<&DateTime<Utc>> = pkgs.values().collect();
// Unwrap safety: We validated pkgs has at least one value above
let largest_timestamp = timestamps.iter().last().unwrap();
let version = pkgs.keys().fold("".to_string(), |mut s, n| {
if !s.is_empty() {
s.push(',');
}
s.push_str(n);
s
});
Ok(ContentMetadata {
timestamp: **largest_timestamp,
version,
})
}

/// Query the rpm database and list the package and build times, for all the
/// files in the EFI system partition, or for grub2-install file
pub(crate) fn rpm_query(sysroot_path: &str, path: &Path) -> Result<Command> {
let mut c = ostreeutil::rpm_cmd(sysroot_path);
c.args(&["-q", "--queryformat", "%{nevra},%{buildtime} ", "-f"]);

match path.file_name().expect("filename").to_str() {
Some("EFI") => {
let efidir = openat::Dir::open(path)?;
c.args(filenames(&efidir)?.drain().map(|mut f| {
f.insert_str(0, "/boot/efi/EFI/");
f
}));
}
_ => {
bail!("Unsupported file/directory {:?}", path)
}
}
Ok(c)
}

0 comments on commit 7d95134

Please sign in to comment.