use pspp::{
crypto::EncryptedFile,
output::{
- driver::{Config, Driver, DriverType},
+ driver::{Config, Driver},
Details, Item, Text,
},
sys::{
io::{stdout, BufReader, Write},
path::{Path, PathBuf},
rc::Rc,
- str::{self, FromStr},
sync::Arc,
};
use thiserror::Error as ThisError;
mode: Mode,
/// Output format.
- #[arg(long, value_parser = ShowFormat::from_str)]
+ #[arg(long)]
format: Option<ShowFormat>,
/// The encoding to use.
let format = if let Some(format) = self.format {
format
} else if let Some(output_file) = &self.output_file {
- ShowFormat::from_str(
- output_file
- .extension()
- .unwrap_or(OsStr::new(""))
- .to_str()
- .unwrap_or(""),
- )
- .map_err(|_| {
- anyhow!(
- "{}: no default output format for file name",
- output_file.display()
- )
- })?
+ match output_file
+ .extension()
+ .unwrap_or(OsStr::new(""))
+ .to_str()
+ .unwrap_or("")
+ {
+ "json" => ShowFormat::Json,
+ "ndjson" => ShowFormat::Ndjson,
+ _ => ShowFormat::Output,
+ }
} else {
ShowFormat::Json
};
- let output = if let ShowFormat::Output(driver) = format {
- let mut config = String::new();
-
- #[derive(Serialize)]
- struct DriverConfig {
- driver: DriverType,
- }
- config.push_str(&toml::to_string_pretty(&DriverConfig { driver }).unwrap());
+ let output = match format {
+ ShowFormat::Output => {
+ let mut config = String::new();
- if let Some(file) = &self.output_file {
- #[derive(Serialize)]
- struct File<'a> {
- file: &'a Path,
+ if let Some(file) = &self.output_file {
+ #[derive(Serialize)]
+ struct File<'a> {
+ file: &'a Path,
+ }
+ let file = File {
+ file: file.as_path(),
+ };
+ let toml_file = toml::to_string_pretty(&file).unwrap();
+ config.push_str(&toml_file);
}
- let file = File {
- file: file.as_path(),
- };
- let toml_file = toml::to_string_pretty(&file).unwrap();
- config.push_str(&toml_file);
-
for option in &self.output_options {
writeln!(&mut config, "{option}").unwrap();
}
- }
- let config: Config = toml::from_str(&config)?;
- Output::Driver {
- mode: self.mode,
- driver: Rc::new(RefCell::new(Box::new(<dyn Driver>::new(&config)?))),
+ let table: toml::Table = toml::from_str(&config)?;
+ if !table.contains_key("driver")
+ && let Some(file) = &self.output_file
+ {
+ let driver =
+ <dyn Driver>::driver_type_from_filename(file).ok_or_else(|| {
+ anyhow!("{}: no default output format for file name", file.display())
+ })?;
+
+ #[derive(Serialize)]
+ struct DriverConfig {
+ driver: &'static str,
+ }
+ config.insert_str(
+ 0,
+ &toml::to_string_pretty(&DriverConfig { driver }).unwrap(),
+ );
+ }
+
+ let config: Config = toml::from_str(&config)?;
+ Output::Driver {
+ mode: self.mode,
+ driver: Rc::new(RefCell::new(Box::new(<dyn Driver>::new(&config)?))),
+ }
}
- } else {
- Output::Json {
+ ShowFormat::Json | ShowFormat::Ndjson => Output::Json {
pretty: format == ShowFormat::Json,
writer: if let Some(output_file) = &self.output_file {
Rc::new(RefCell::new(Box::new(File::create(output_file)?)))
} else {
Rc::new(RefCell::new(Box::new(stdout())))
},
- }
+ },
};
let reader = File::open(&self.input_file)?;
}
}
-#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize)]
+#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, ValueEnum)]
#[serde(rename_all = "snake_case")]
enum ShowFormat {
/// Pretty-printed JSON.
Json,
/// Newline-delimited JSON.
Ndjson,
- Output(DriverType),
-}
-
-#[derive(ThisError, Debug)]
-#[error("{0}: unknown format")]
-struct UnknownFormat(String);
-
-impl FromStr for ShowFormat {
- type Err = UnknownFormat;
-
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- if s.eq_ignore_ascii_case("json") {
- Ok(Self::Json)
- } else if s.eq_ignore_ascii_case("ndjson") {
- Ok(Self::Ndjson)
- } else if let Ok(driver_type) = DriverType::from_str(s, true) {
- Ok(Self::Output(driver_type))
- } else {
- Err(UnknownFormat(String::from(s)))
- }
- }
+ Output,
}
fn main() -> Result<()> {