automerge/automerge-cli/src/merge.rs
2022-03-04 12:28:05 +00:00

58 lines
1.5 KiB
Rust

use automerge as am;
use std::{
io::Read,
path::{Path, PathBuf},
};
pub(super) enum Inputs {
Stdin,
Paths(Vec<PathBuf>),
}
impl From<Vec<PathBuf>> for Inputs {
fn from(i: Vec<PathBuf>) -> Self {
if i.is_empty() {
Inputs::Stdin
} else {
Inputs::Paths(i)
}
}
}
#[derive(Debug, thiserror::Error)]
pub(super) enum MergeError {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("failed to load {path}: {error}")]
FailedToLoad {
path: PathBuf,
error: Box<dyn std::error::Error>,
},
#[error(transparent)]
Automerge(#[from] am::AutomergeError),
}
pub(super) fn merge<W: std::io::Write>(inputs: Inputs, mut output: W) -> Result<(), MergeError> {
let mut backend = am::Automerge::new();
match inputs {
Inputs::Stdin => {
let mut input = Vec::new();
std::io::stdin().read_to_end(&mut input)?;
backend.load_incremental(&input)?;
}
Inputs::Paths(paths) => {
for path in paths {
load_path(&mut backend, &path)
.map_err(|error| MergeError::FailedToLoad { path, error })?;
}
}
}
output.write_all(&backend.save())?;
Ok(())
}
fn load_path(backend: &mut am::Automerge, path: &Path) -> Result<(), Box<dyn std::error::Error>> {
let input = std::fs::read(path).map_err(Box::new)?;
backend.load_incremental(&input).map_err(Box::new)?;
Ok(())
}