feat(nix-compat/narinfo): turn flags into bitfields

Change-Id: I8b95723444013e97bc6ec8d282c7135b1aede114
Reviewed-on: https://cl.tvl.fyi/c/depot/+/9987
Reviewed-by: flokli <flokli@flokli.de>
Tested-by: BuildkiteCI
This commit is contained in:
edef 2023-11-10 16:19:02 +00:00
parent 1df53a5fcd
commit 2997c1c304
4 changed files with 30 additions and 21 deletions

1
tvix/Cargo.lock generated
View file

@ -1431,6 +1431,7 @@ dependencies = [
name = "nix-compat" name = "nix-compat"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitflags 2.4.1",
"bstr", "bstr",
"criterion", "criterion",
"data-encoding", "data-encoding",

View file

@ -4209,6 +4209,10 @@ rec {
then lib.cleanSourceWith { filter = sourceFilter; src = ./nix-compat; } then lib.cleanSourceWith { filter = sourceFilter; src = ./nix-compat; }
else ./nix-compat; else ./nix-compat;
dependencies = [ dependencies = [
{
name = "bitflags";
packageId = "bitflags 2.4.1";
}
{ {
name = "bstr"; name = "bstr";
packageId = "bstr"; packageId = "bstr";

View file

@ -9,6 +9,7 @@ edition = "2021"
async = ["futures-util"] async = ["futures-util"]
[dependencies] [dependencies]
bitflags = "2.4.1"
bstr = { version = "1.6.0", features = ["alloc", "unicode", "serde"] } bstr = { version = "1.6.0", features = ["alloc", "unicode", "serde"] }
data-encoding = "2.3.3" data-encoding = "2.3.3"
futures-util = { version = "0.3.28", features = ["io"], optional = true } futures-util = { version = "0.3.28", features = ["io"], optional = true }

View file

@ -17,6 +17,7 @@
//! * compression algorithm used for the NAR //! * compression algorithm used for the NAR
//! * hash and size of the compressed NAR //! * hash and size of the compressed NAR
use bitflags::bitflags;
use data_encoding::{BASE64, HEXLOWER}; use data_encoding::{BASE64, HEXLOWER};
use std::{ use std::{
fmt::{self, Display}, fmt::{self, Display},
@ -31,10 +32,7 @@ use crate::{
#[derive(Debug)] #[derive(Debug)]
pub struct NarInfo<'a> { pub struct NarInfo<'a> {
pub unknown_fields: bool, pub flags: Flags,
pub compression_default: bool,
pub nar_hash_hex: bool,
pub references_out_of_order: bool,
// core (authenticated, but unverified here) // core (authenticated, but unverified here)
/// Store path described by this [NarInfo] /// Store path described by this [NarInfo]
pub store_path: StorePathRef<'a>, pub store_path: StorePathRef<'a>,
@ -70,13 +68,21 @@ pub struct NarInfo<'a> {
pub file_size: Option<u64>, pub file_size: Option<u64>,
} }
bitflags! {
/// TODO(edef): be conscious of these when roundtripping
#[derive(Debug, Copy, Clone)]
pub struct Flags: u8 {
const UNKNOWN_FIELD = 1 << 0;
const COMPRESSION_DEFAULT = 1 << 1;
// Format quirks encountered in the cache.nixos.org dataset
const REFERENCES_OUT_OF_ORDER = 1 << 2;
const NAR_HASH_HEX = 1 << 3;
}
}
impl<'a> NarInfo<'a> { impl<'a> NarInfo<'a> {
pub fn parse(input: &'a str) -> Result<Self, Error> { pub fn parse(input: &'a str) -> Result<Self, Error> {
let mut unknown_fields = false; let mut flags = Flags::empty();
let mut compression_default = false;
let mut nar_hash_hex = false;
let mut references_out_of_order = false;
let mut store_path = None; let mut store_path = None;
let mut url = None; let mut url = None;
let mut compression = None; let mut compression = None;
@ -159,7 +165,7 @@ impl<'a> NarInfo<'a> {
let val = if val.len() != HEXLOWER.encode_len(32) { let val = if val.len() != HEXLOWER.encode_len(32) {
nixbase32::decode_fixed::<32>(val) nixbase32::decode_fixed::<32>(val)
} else { } else {
nar_hash_hex = true; flags |= Flags::NAR_HASH_HEX;
let val = val.as_bytes(); let val = val.as_bytes();
let mut buf = [0u8; 32]; let mut buf = [0u8; 32];
@ -193,7 +199,7 @@ impl<'a> NarInfo<'a> {
.map(|(i, s)| { .map(|(i, s)| {
// TODO(edef): track *duplicates* if this occurs // TODO(edef): track *duplicates* if this occurs
if mem::replace(&mut prev, s) >= s { if mem::replace(&mut prev, s) >= s {
references_out_of_order = true; flags |= Flags::REFERENCES_OUT_OF_ORDER;
} }
StorePathRef::from_bytes(s.as_bytes()) StorePathRef::from_bytes(s.as_bytes())
@ -244,15 +250,12 @@ impl<'a> NarInfo<'a> {
} }
} }
_ => { _ => {
unknown_fields = true; flags |= Flags::UNKNOWN_FIELD;
} }
} }
} }
Ok(NarInfo { Ok(NarInfo {
unknown_fields,
nar_hash_hex,
references_out_of_order,
store_path: store_path.ok_or(Error::MissingField("StorePath"))?, store_path: store_path.ok_or(Error::MissingField("StorePath"))?,
nar_hash: nar_hash.ok_or(Error::MissingField("NarHash"))?, nar_hash: nar_hash.ok_or(Error::MissingField("NarHash"))?,
nar_size: nar_size.ok_or(Error::MissingField("NarSize"))?, nar_size: nar_size.ok_or(Error::MissingField("NarSize"))?,
@ -265,14 +268,14 @@ impl<'a> NarInfo<'a> {
compression: match compression { compression: match compression {
Some("none") => None, Some("none") => None,
None => { None => {
compression_default = true; flags |= Flags::COMPRESSION_DEFAULT;
Some("bzip2") Some("bzip2")
} }
_ => compression, _ => compression,
}, },
compression_default,
file_hash, file_hash,
file_size, file_size,
flags,
}) })
} }
} }
@ -502,7 +505,7 @@ mod test {
store_path::StorePathRef, store_path::StorePathRef,
}; };
use super::NarInfo; use super::{Flags, NarInfo};
lazy_static! { lazy_static! {
static ref CASES: &'static [&'static str] = { static ref CASES: &'static [&'static str] = {
@ -541,7 +544,7 @@ Deriver: 2dzpn70c1hawczwhg9aavqk18zp9zsva-gcc-3.4.6.drv
Sig: cache.nixos.org-1:o1DTsjCz0PofLJ216P2RBuSulI8BAb6zHxWE4N+tzlcELk5Uk/GO2SCxWTRN5wJutLZZ+cHTMdWqOHF88KGQDg== Sig: cache.nixos.org-1:o1DTsjCz0PofLJ216P2RBuSulI8BAb6zHxWE4N+tzlcELk5Uk/GO2SCxWTRN5wJutLZZ+cHTMdWqOHF88KGQDg==
"#).expect("should parse"); "#).expect("should parse");
assert!(parsed.references_out_of_order); assert!(parsed.flags.contains(Flags::REFERENCES_OUT_OF_ORDER));
assert_eq!( assert_eq!(
vec![ vec![
"a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7", "a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7",
@ -597,7 +600,7 @@ System: i686-linux
Sig: cache.nixos.org-1:92fl0i5q7EyegCj5Yf4L0bENkWuVAtgveiRcTEEUH0P6HvCE1xFcPbz/0Pf6Np+K1LPzHK+s5RHOmVoxRsvsDg== Sig: cache.nixos.org-1:92fl0i5q7EyegCj5Yf4L0bENkWuVAtgveiRcTEEUH0P6HvCE1xFcPbz/0Pf6Np+K1LPzHK+s5RHOmVoxRsvsDg==
"#).expect("should parse"); "#).expect("should parse");
assert!(parsed.compression_default); assert!(parsed.flags.contains(Flags::COMPRESSION_DEFAULT));
assert_eq!(parsed.compression, Some("bzip2")); assert_eq!(parsed.compression, Some("bzip2"));
} }
@ -615,7 +618,7 @@ Deriver: fb4ihlq3psnsjq95mvvs49rwpplpc8zj-perl-HTTP-Cookies-6.01.drv
Sig: cache.nixos.org-1:HhaiY36Uk3XV1JGe9d9xHnzAapqJXprU1YZZzSzxE97jCuO5RR7vlG2kF7MSC5thwRyxAtdghdSz3AqFi+QSCw== Sig: cache.nixos.org-1:HhaiY36Uk3XV1JGe9d9xHnzAapqJXprU1YZZzSzxE97jCuO5RR7vlG2kF7MSC5thwRyxAtdghdSz3AqFi+QSCw==
"#).expect("should parse"); "#).expect("should parse");
assert!(parsed.nar_hash_hex); assert!(parsed.flags.contains(Flags::NAR_HASH_HEX));
assert_eq!( assert_eq!(
hex!("60adfd293a4d81ad7cd7e47263cbb3fc846309ef91b154a08ba672b558f94ff3"), hex!("60adfd293a4d81ad7cd7e47263cbb3fc846309ef91b154a08ba672b558f94ff3"),
parsed.nar_hash, parsed.nar_hash,