// SPDX-FileCopyrightText: 2024 Ɓukasz Niemier <#@hauleth.dev> // // SPDX-License-Identifier: EUPL-1.2 use std::collections::HashMap; use std::io::{self, prelude::*}; use rayon::prelude::*; #[derive(PartialEq, Eq, Debug, Copy, Clone)] pub enum Format { JSON, TOML, CSV, SSH, } impl Format { pub fn render(self, output: &Output, w: &mut W) -> io::Result<()> { match self { Format::JSON => { serde_json::to_writer_pretty(&mut *w, &output.keys).map_err(io::Error::other)?; writeln!(w) } Format::TOML => write!(w, "{}", toml::to_string_pretty(&output.keys).unwrap()), Format::CSV => as_csv(w, output), Format::SSH => authorized_keys(w, output), } } } impl std::fmt::Display for Format { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match *self { Format::JSON => f.write_str("json"), Format::TOML => f.write_str("toml"), Format::CSV => f.write_str("csv"), Format::SSH => f.write_str("ssh"), } } } impl<'a> From<&'a str> for Format { fn from(s: &'a str) -> Format { match s { "json" => Format::JSON, "toml" => Format::TOML, "csv" => Format::CSV, "ssh" => Format::SSH, _ => unreachable!(), } } } #[derive(Debug, serde::Serialize)] pub struct Output { pub keys: HashMap>, } impl FromParallelIterator<(String, Vec)> for Output { fn from_par_iter(iter: T) -> Self where T: IntoParallelIterator)>, { Output { keys: iter.into_par_iter().collect(), } } } // TODO: proper escaping fn as_csv(w: &mut W, output: &Output) -> io::Result<()> { for (name, keys) in &output.keys { for key in keys { writeln!(w, "{name},{}", key.to_string())?; } } Ok(()) } fn authorized_keys(w: &mut W, output: &Output) -> io::Result<()> { for (name, keys) in &output.keys { for key in keys { let commented = ssh_key::PublicKey::new(key.key_data().clone(), name); writeln!(w, "{}", commented.to_string())?; } } Ok(()) }