Add option to export to stdout

This commit is contained in:
Joscha 2023-02-12 00:54:09 +01:00
parent 0ceaffc608
commit ca10ca277b
4 changed files with 47 additions and 40 deletions

View file

@ -17,6 +17,7 @@ Procedure when bumping the version number:
### Added
- `--verbose` flag
- `json-stream` room export format
- Option to export to stdout
### Changed
- Respect colon-delimited emoji when calculating nick hue

View file

@ -4,9 +4,9 @@ mod json;
mod text;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::io::{self, BufWriter, Write};
use crate::vault::EuphVault;
use crate::vault::{EuphRoomVault, EuphVault};
#[derive(Debug, Clone, Copy, clap::ValueEnum)]
pub enum Format {
@ -57,12 +57,28 @@ pub struct Args {
/// If the value ends with a `/`, it is assumed to point to a directory and
/// `%r.%e` will be appended.
///
/// If the value is a literal `-`, the export will be written to stdout. To
/// write to a file named `-`, you can use `./-`.
///
/// Must be a valid utf-8 encoded string.
#[arg(long, short, default_value_t = Into::into("%r.%e"))]
#[arg(verbatim_doc_comment)]
out: String,
}
async fn export_room<W: Write>(
vault: &EuphRoomVault,
out: &mut W,
format: Format,
) -> anyhow::Result<()> {
match format {
Format::Text => text::export(vault, out).await?,
Format::Json => json::export(vault, out).await?,
Format::JsonStream => json::export_stream(vault, out).await?,
}
Ok(())
}
pub async fn export(vault: &EuphVault, mut args: Args) -> anyhow::Result<()> {
if args.out.ends_with('/') {
args.out.push_str("%r.%e");
@ -79,21 +95,24 @@ pub async fn export(vault: &EuphVault, mut args: Args) -> anyhow::Result<()> {
};
if rooms.is_empty() {
println!("No rooms to export");
eprintln!("No rooms to export");
}
for room in rooms {
let out = format_out(&args.out, &room, args.format);
println!("Exporting &{room} as {} to {out}", args.format.name());
let vault = vault.room(room);
let mut file = BufWriter::new(File::create(out)?);
match args.format {
Format::Text => text::export_to_file(&vault, &mut file).await?,
Format::Json => json::export_to_file(&vault, &mut file).await?,
Format::JsonStream => json::export_stream_to_file(&vault, &mut file).await?,
if args.out == "-" {
eprintln!("Exporting &{room} as {} to stdout", args.format.name());
let vault = vault.room(room);
let mut stdout = BufWriter::new(io::stdout());
export_room(&vault, &mut stdout, args.format).await?;
stdout.flush()?;
} else {
let out = format_out(&args.out, &room, args.format);
eprintln!("Exporting &{room} as {} to {out}", args.format.name());
let vault = vault.room(room);
let mut file = BufWriter::new(File::create(out)?);
export_room(&vault, &mut file, args.format).await?;
file.flush()?;
}
file.flush()?;
}
Ok(())

View file

@ -1,14 +1,10 @@
use std::fs::File;
use std::io::{BufWriter, Write};
use std::io::Write;
use crate::vault::EuphRoomVault;
const CHUNK_SIZE: usize = 10000;
pub async fn export_to_file(
vault: &EuphRoomVault,
file: &mut BufWriter<File>,
) -> anyhow::Result<()> {
pub async fn export<W: Write>(vault: &EuphRoomVault, file: &mut W) -> anyhow::Result<()> {
write!(file, "[")?;
let mut total = 0;
@ -39,14 +35,10 @@ pub async fn export_to_file(
write!(file, "\n]")?;
println!(" {total} messages in total");
Ok(())
}
pub async fn export_stream_to_file(
vault: &EuphRoomVault,
file: &mut BufWriter<File>,
) -> anyhow::Result<()> {
pub async fn export_stream<W: Write>(vault: &EuphRoomVault, file: &mut W) -> anyhow::Result<()> {
let mut total = 0;
let mut offset = 0;
loop {
@ -69,6 +61,5 @@ pub async fn export_stream_to_file(
}
println!(" {total} messages in total");
Ok(())
}

View file

@ -1,5 +1,4 @@
use std::fs::File;
use std::io::{BufWriter, Write};
use std::io::Write;
use euphoxide::api::MessageId;
use time::format_description::FormatItem;
@ -14,16 +13,13 @@ const TIME_FORMAT: &[FormatItem<'_>] =
format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
const TIME_EMPTY: &str = " ";
pub async fn export_to_file(
vault: &EuphRoomVault,
file: &mut BufWriter<File>,
) -> anyhow::Result<()> {
pub async fn export<W: Write>(vault: &EuphRoomVault, out: &mut W) -> anyhow::Result<()> {
let mut exported_trees = 0;
let mut exported_msgs = 0;
let mut root_id = vault.first_root_id().await;
while let Some(some_root_id) = root_id {
let tree = vault.tree(some_root_id).await;
write_tree(file, &tree, some_root_id, 0)?;
write_tree(out, &tree, some_root_id, 0)?;
root_id = vault.next_root_id(some_root_id).await;
exported_trees += 1;
@ -38,8 +34,8 @@ pub async fn export_to_file(
Ok(())
}
fn write_tree(
file: &mut BufWriter<File>,
fn write_tree<W: Write>(
out: &mut W,
tree: &Tree<SmallMessage>,
id: MessageId,
indent: usize,
@ -47,22 +43,22 @@ fn write_tree(
let indent_string = "| ".repeat(indent);
if let Some(msg) = tree.msg(&id) {
write_msg(file, &indent_string, msg)?;
write_msg(out, &indent_string, msg)?;
} else {
write_placeholder(file, &indent_string)?;
write_placeholder(out, &indent_string)?;
}
if let Some(children) = tree.children(&id) {
for child in children {
write_tree(file, tree, *child, indent + 1)?;
write_tree(out, tree, *child, indent + 1)?;
}
}
Ok(())
}
fn write_msg(
file: &mut BufWriter<File>,
fn write_msg<W: Write>(
file: &mut W,
indent_string: &str,
msg: &SmallMessage,
) -> anyhow::Result<()> {
@ -85,7 +81,7 @@ fn write_msg(
Ok(())
}
fn write_placeholder(file: &mut BufWriter<File>, indent_string: &str) -> anyhow::Result<()> {
fn write_placeholder<W: Write>(file: &mut W, indent_string: &str) -> anyhow::Result<()> {
writeln!(file, "{TIME_EMPTY} {indent_string}[...]")?;
Ok(())
}