use super::balls::{Ball, parse_ball, parse_list};
use crate::cli_outbound::{Chunk, Cli, CliError, ExitInfo, Stream};
use std::io;
use std::path::Path;
pub trait BlRunner {
fn list(&self, project: &Path) -> io::Result<String>;
fn list_closed(&self, project: &Path) -> io::Result<String>;
fn show(&self, project: &Path, id: &str) -> io::Result<String>;
fn live(&self, project: &Path) -> Vec<Ball> {
self.list(project)
.map(|j| parse_list(&j))
.unwrap_or_default()
}
fn closed(&self, project: &Path) -> Vec<Ball> {
self.list_closed(project)
.map(|j| parse_list(&j))
.unwrap_or_default()
}
fn detail(&self, project: &Path, id: &str) -> Option<Ball> {
parse_ball(&self.show(project, id).ok()?)
}
}
pub struct BlCli {
cli: Cli,
}
impl BlCli {
pub fn new(cli: Cli) -> Self {
Self { cli }
}
}
fn collect_stdout(stream: Result<Stream, CliError>) -> io::Result<String> {
let stream = stream.map_err(io::Error::other)?;
let mut out = Vec::new();
let mut exit = ExitInfo::Unknown;
for chunk in stream {
match chunk {
Chunk::Stdout(b) => out.extend(b),
Chunk::Stderr(_) => {}
Chunk::Exited(e) => exit = e,
}
}
match exit {
ExitInfo::Code(0) => Ok(String::from_utf8_lossy(&out).into_owned()),
other => Err(io::Error::other(format!("bl exited: {other:?}"))),
}
}
impl BlRunner for BlCli {
fn list(&self, project: &Path) -> io::Result<String> {
collect_stdout(self.cli.run_in(project, &["list", "--json"]))
}
fn list_closed(&self, project: &Path) -> io::Result<String> {
collect_stdout(
self.cli
.run_in(project, &["list", "-s", "closed", "--json"]),
)
}
fn show(&self, project: &Path, id: &str) -> io::Result<String> {
collect_stdout(self.cli.run_in(project, &["show", id, "--json"]))
}
}
pub fn identity(recorded: Option<String>, user: Option<String>) -> String {
recorded.or(user).unwrap_or_default()
}
#[cfg(test)]
mod tests;