{ depot, pkgs, ... }: let cdbListToNetencode = depot.nix.writers.rustSimple { name = "cdb-list-to-netencode"; dependencies = [ depot.third_party.rust-crates.nom depot.users.Profpatsch.execline.exec-helpers depot.users.Profpatsch.netencode.netencode-rs ]; } '' extern crate nom; extern crate exec_helpers; extern crate netencode; use std::collections::HashMap; use std::io::BufRead; use nom::{IResult}; use nom::sequence::{tuple}; use nom::bytes::complete::{tag, take}; use nom::character::complete::{digit1, char}; use nom::error::{context, ErrorKind, ParseError}; use nom::combinator::{map_res}; use netencode::{T, Tag}; fn usize_t(s: &[u8]) -> IResult<&[u8], usize> { context( "usize", map_res( map_res(digit1, |n| std::str::from_utf8(n)), |s| s.parse::<usize>()) )(s) } fn parse_cdb_record(s: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> { let (s, (_, klen, _, vlen, _)) = tuple(( char('+'), usize_t, char(','), usize_t, char(':') ))(s)?; let (s, (key, _, val)) = tuple(( take(klen), tag("->"), take(vlen), ))(s)?; Ok((s, (key, val))) } fn main() { let mut res = vec![]; let stdin = std::io::stdin(); let mut lines = stdin.lock().split(b'\n'); loop { match lines.next() { None => exec_helpers::die_user_error("cdb-list-to-netencode", "stdin ended but we didn’t receive the empty line to signify the end of the cdbdump input!"), Some(Err(err)) => exec_helpers::die_temporary("cdb-list-to-netencode", format!("could not read from stdin: {}", err)), Some(Ok(line)) => if &line == b"" { // the cdbdump input ends after an empty line (double \n) break; } else { match parse_cdb_record(&line) { Ok((b"", (key, val))) => { let (key, val) = match std::str::from_utf8(key) .and_then(|k| std::str::from_utf8(val).map(|v| (k, v))) { Ok((key, val)) => (key.to_owned(), val.to_owned()), Err(err) => exec_helpers::die_user_error("cdb-list-to-netencode", format!("cannot decode line {:?}, we only support utf8-encoded key/values pairs for now: {}", String::from_utf8_lossy(&line), err)), }; let _ = res.push((key, val)); }, Ok((rest, _)) => exec_helpers::die_user_error("cdb-list-to-netencode", format!("could not decode record line {:?}, had some trailing bytes", String::from_utf8_lossy(&line))), Err(err) => exec_helpers::die_user_error("cdb-list-to-netencode", format!("could not decode record line {:?}: {:?}", String::from_utf8_lossy(&line), err)), } } } } let list = T::List(res.into_iter().map( |(k, v)| T::Record(vec![(String::from("key"), T::Text(k)), (String::from("val"), T::Text(v))].into_iter().collect()) ).collect()); netencode::encode(&mut std::io::stdout(), &list.to_u()); } ''; in { inherit cdbListToNetencode ; }