narinfo-rs/src/narinfo/from_str.rs

131 lines
3.8 KiB
Rust

use super::{NarInfo, NarInfoBuilder};
use crate::{
error::{ParsingError, ParsingResult},
sig::Sig,
};
use alloc::{borrow::Cow, vec::Vec};
impl<'a> NarInfo<'a> {
/// Parses the contents of a narinfo file from str.
/// This function is also used to implement the [TryFrom] trait for &'a str.
///
/// For duplicate keys the last value is used(same behaviour as libstore).
/// Unknown keys return an error(unlike libstore where they're simply ignored).
///
/// ```
/// # fn http_get_str(_url: &str) -> &'static str { include_str!("../../sample.narinfo") }
/// use narinfo::NarInfo;
/// let data: &str =
/// http_get_str("https://cache.nixos.org/zn2h0kln2b02x4x6jqxymd4sg9cwvdsx.narinfo");
///
/// let parsed = NarInfo::parse(data).unwrap();
/// assert_eq!(parsed.store_path, "/nix/store/zzxrhj9056vjlanfjkinvhd7458yc2z8-liblouis-3.22.0");
/// ```
pub fn parse(value: &'a str) -> ParsingResult<Self> {
let mut builder = NarInfoBuilder::default();
let mut sigs = Vec::new();
for line in value.lines() {
let (key, value) = line
.split_once(':')
.map(|(k, v)| (k, v.trim()))
.ok_or(ParsingError::InvalidLine { line })?;
match key {
"StorePath" => builder.store_path(Cow::from(value)),
"URL" => builder.url(value),
"Compression" => builder.compression(Some(Cow::from(value))),
"FileHash" => builder.file_hash(Some(value)),
"NarHash" => builder.nar_hash(Cow::from(value)),
"NarSize" => {
let size: usize = ParsingError::try_parse_int(value, line)?;
builder.nar_size(size)
}
"FileSize" => {
let size: usize = ParsingError::try_parse_int(value, line)?;
builder.file_size(Some(size))
}
"Deriver" => builder.deriver(Some(Cow::from(value))),
"System" => builder.system(Some(Cow::from(value))),
"References" => builder.references(value.split(' ').map(Cow::from).collect()),
"Sig" => {
sigs.push(Sig::try_from(value)?);
&mut builder
},
_ => return Err(ParsingError::UnknownKey { key }),
};
}
builder.sigs(sigs);
builder.build()
}
}
impl<'a> TryFrom<&'a str> for NarInfo<'a> {
type Error = crate::error::ParsingError<'a>;
fn try_from(value: &'a str) -> ParsingResult<Self> {
NarInfo::parse(value)
}
}
#[cfg(test)]
mod tests {
use alloc::borrow::Cow;
use super::*;
#[test]
fn parses_sample_narinfo() {
let sample = include_str!("../../sample.narinfo");
let info = NarInfo::try_from(sample).unwrap();
assert_eq!(
info.store_path,
"/nix/store/zzxrhj9056vjlanfjkinvhd7458yc2z8-liblouis-3.22.0"
);
assert_eq!(
info.url,
"nar/0ccqg4il1m9qqh8b6x0x8nn7pjcphr82h2qdfc5gqq8dy7h2kp9x.nar.xz"
);
assert_eq!(info.compression, Some(Cow::Borrowed("xz")));
assert_eq!(
info.file_hash,
Some("sha256:0ccqg4il1m9qqh8b6x0x8nn7pjcphr82h2qdfc5gqq8dy7h2kp9x")
);
assert_eq!(info.file_size, Some(1914556));
assert_eq!(
info.nar_hash,
"sha256:0c8ld5yxcr6a6j63mvrqbqiy08q6f85wd74817ai7pvd5nkidcqw"
);
assert_eq!(info.nar_size, 11374872);
let expected_refs = [
"mhhlymrg2m70r8h94cwhv2d7a0c8l7g6-glibc-2.34-210",
"ppn8983d9b5r6k7mnhkbg6rqw7vgl1ij-libyaml-0.2.5",
"qm2lv1gpbyn0rsfai40cbvj3h4gz69yc-bash-5.1-p16",
"sn0w3f12547crckss4ybmnxmi29gpgq7-perl-5.34.1",
"zzxrhj9056vjlanfjkinvhd7458yc2z8-liblouis-3.22.0",
];
for (a, b) in info.references.iter().zip(expected_refs) {
assert_eq!(a, b);
}
assert_eq!(
info.deriver,
Some(Cow::Borrowed(
"dlxmsgfc0am35fh0kiy88zqr91x2dn5j-liblouis-3.22.0.drv"
))
);
let sig = &info.sigs[0];
assert_eq!(sig.key_name, "cache.nixos.org-1");
assert_eq!(sig.sig, "BJ5QGcOta2s76XC6sep9DbAv0x3TILh3hHSKyR+9rFWYuBDTWdHs1KHeUEpw2espE/zPPBp2yURO6/J4Dhf9DQ==");
let sig = &info.sigs[1];
assert_eq!(sig.key_name, "fake-test-sig-1");
assert_eq!(sig.sig, "BJ5QGcOta2s76XC6sep9DbAv0x3TILh3hHSKyR+9rFWYuBDTWdHs1KHeUEpw2espE/zPPBp2yURO6/J4Dhf9DQ==");
assert!(info.sigs.len() == 2);
}
}