Add option to export to stdout
This commit is contained in:
parent
0ceaffc608
commit
ca10ca277b
4 changed files with 47 additions and 40 deletions
|
|
@ -17,6 +17,7 @@ Procedure when bumping the version number:
|
||||||
### Added
|
### Added
|
||||||
- `--verbose` flag
|
- `--verbose` flag
|
||||||
- `json-stream` room export format
|
- `json-stream` room export format
|
||||||
|
- Option to export to stdout
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Respect colon-delimited emoji when calculating nick hue
|
- Respect colon-delimited emoji when calculating nick hue
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ mod json;
|
||||||
mod text;
|
mod text;
|
||||||
|
|
||||||
use std::fs::File;
|
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)]
|
#[derive(Debug, Clone, Copy, clap::ValueEnum)]
|
||||||
pub enum Format {
|
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
|
/// If the value ends with a `/`, it is assumed to point to a directory and
|
||||||
/// `%r.%e` will be appended.
|
/// `%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.
|
/// Must be a valid utf-8 encoded string.
|
||||||
#[arg(long, short, default_value_t = Into::into("%r.%e"))]
|
#[arg(long, short, default_value_t = Into::into("%r.%e"))]
|
||||||
#[arg(verbatim_doc_comment)]
|
#[arg(verbatim_doc_comment)]
|
||||||
out: String,
|
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<()> {
|
pub async fn export(vault: &EuphVault, mut args: Args) -> anyhow::Result<()> {
|
||||||
if args.out.ends_with('/') {
|
if args.out.ends_with('/') {
|
||||||
args.out.push_str("%r.%e");
|
args.out.push_str("%r.%e");
|
||||||
|
|
@ -79,22 +95,25 @@ pub async fn export(vault: &EuphVault, mut args: Args) -> anyhow::Result<()> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if rooms.is_empty() {
|
if rooms.is_empty() {
|
||||||
println!("No rooms to export");
|
eprintln!("No rooms to export");
|
||||||
}
|
}
|
||||||
|
|
||||||
for room in rooms {
|
for room in rooms {
|
||||||
|
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);
|
let out = format_out(&args.out, &room, args.format);
|
||||||
println!("Exporting &{room} as {} to {out}", args.format.name());
|
eprintln!("Exporting &{room} as {} to {out}", args.format.name());
|
||||||
|
|
||||||
let vault = vault.room(room);
|
let vault = vault.room(room);
|
||||||
let mut file = BufWriter::new(File::create(out)?);
|
let mut file = BufWriter::new(File::create(out)?);
|
||||||
match args.format {
|
export_room(&vault, &mut file, args.format).await?;
|
||||||
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?,
|
|
||||||
}
|
|
||||||
file.flush()?;
|
file.flush()?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
use std::fs::File;
|
use std::io::Write;
|
||||||
use std::io::{BufWriter, Write};
|
|
||||||
|
|
||||||
use crate::vault::EuphRoomVault;
|
use crate::vault::EuphRoomVault;
|
||||||
|
|
||||||
const CHUNK_SIZE: usize = 10000;
|
const CHUNK_SIZE: usize = 10000;
|
||||||
|
|
||||||
pub async fn export_to_file(
|
pub async fn export<W: Write>(vault: &EuphRoomVault, file: &mut W) -> anyhow::Result<()> {
|
||||||
vault: &EuphRoomVault,
|
|
||||||
file: &mut BufWriter<File>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
write!(file, "[")?;
|
write!(file, "[")?;
|
||||||
|
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
|
|
@ -39,14 +35,10 @@ pub async fn export_to_file(
|
||||||
write!(file, "\n]")?;
|
write!(file, "\n]")?;
|
||||||
|
|
||||||
println!(" {total} messages in total");
|
println!(" {total} messages in total");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn export_stream_to_file(
|
pub async fn export_stream<W: Write>(vault: &EuphRoomVault, file: &mut W) -> anyhow::Result<()> {
|
||||||
vault: &EuphRoomVault,
|
|
||||||
file: &mut BufWriter<File>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -69,6 +61,5 @@ pub async fn export_stream_to_file(
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(" {total} messages in total");
|
println!(" {total} messages in total");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use std::fs::File;
|
use std::io::Write;
|
||||||
use std::io::{BufWriter, Write};
|
|
||||||
|
|
||||||
use euphoxide::api::MessageId;
|
use euphoxide::api::MessageId;
|
||||||
use time::format_description::FormatItem;
|
use time::format_description::FormatItem;
|
||||||
|
|
@ -14,16 +13,13 @@ const TIME_FORMAT: &[FormatItem<'_>] =
|
||||||
format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
|
format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
|
||||||
const TIME_EMPTY: &str = " ";
|
const TIME_EMPTY: &str = " ";
|
||||||
|
|
||||||
pub async fn export_to_file(
|
pub async fn export<W: Write>(vault: &EuphRoomVault, out: &mut W) -> anyhow::Result<()> {
|
||||||
vault: &EuphRoomVault,
|
|
||||||
file: &mut BufWriter<File>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let mut exported_trees = 0;
|
let mut exported_trees = 0;
|
||||||
let mut exported_msgs = 0;
|
let mut exported_msgs = 0;
|
||||||
let mut root_id = vault.first_root_id().await;
|
let mut root_id = vault.first_root_id().await;
|
||||||
while let Some(some_root_id) = root_id {
|
while let Some(some_root_id) = root_id {
|
||||||
let tree = vault.tree(some_root_id).await;
|
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;
|
root_id = vault.next_root_id(some_root_id).await;
|
||||||
|
|
||||||
exported_trees += 1;
|
exported_trees += 1;
|
||||||
|
|
@ -38,8 +34,8 @@ pub async fn export_to_file(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_tree(
|
fn write_tree<W: Write>(
|
||||||
file: &mut BufWriter<File>,
|
out: &mut W,
|
||||||
tree: &Tree<SmallMessage>,
|
tree: &Tree<SmallMessage>,
|
||||||
id: MessageId,
|
id: MessageId,
|
||||||
indent: usize,
|
indent: usize,
|
||||||
|
|
@ -47,22 +43,22 @@ fn write_tree(
|
||||||
let indent_string = "| ".repeat(indent);
|
let indent_string = "| ".repeat(indent);
|
||||||
|
|
||||||
if let Some(msg) = tree.msg(&id) {
|
if let Some(msg) = tree.msg(&id) {
|
||||||
write_msg(file, &indent_string, msg)?;
|
write_msg(out, &indent_string, msg)?;
|
||||||
} else {
|
} else {
|
||||||
write_placeholder(file, &indent_string)?;
|
write_placeholder(out, &indent_string)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(children) = tree.children(&id) {
|
if let Some(children) = tree.children(&id) {
|
||||||
for child in children {
|
for child in children {
|
||||||
write_tree(file, tree, *child, indent + 1)?;
|
write_tree(out, tree, *child, indent + 1)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_msg(
|
fn write_msg<W: Write>(
|
||||||
file: &mut BufWriter<File>,
|
file: &mut W,
|
||||||
indent_string: &str,
|
indent_string: &str,
|
||||||
msg: &SmallMessage,
|
msg: &SmallMessage,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
|
|
@ -85,7 +81,7 @@ fn write_msg(
|
||||||
Ok(())
|
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}[...]")?;
|
writeln!(file, "{TIME_EMPTY} {indent_string}[...]")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue