D6UTHZA4XNAR2PTG4YEZFNNH3OTSNOWGDSVBYDRE5R2YSV7MPN6AC
use beancount_pretty_printer::PrettyPrinter;
use beancount_types::Account;
use beancount_types::Directive;
use camino::Utf8Path;
use camino::Utf8PathBuf;
use color_eyre::eyre::format_err;
use color_eyre::Help;
use color_eyre::Report;
use color_eyre::Result;
use dashmap::DashMap;
use rayon::prelude::IntoParallelIterator as _;
use rayon::prelude::ParallelIterator as _;
use rayon::slice::ParallelSliceMut as _;
use snafu::Backtrace;
use snafu::ResultExt as _;
use snafu::Snafu;
use std::fmt::Write as _;
use std::fs;
use std::fs::File;
use std::io;
use time::Month;
pub struct Config {
pub base_directory: Utf8PathBuf,
}
#[derive(Debug, Snafu)]
pub struct TreeWriterError(Error);
#[derive(Debug, Snafu)]
enum Error {
#[snafu(display("encountered unsupported directive while indexing: {directive:?}"))]
IndexingDirective {
backtrace: Backtrace,
directive: Directive,
},
#[snafu(display("error while pretty printing directives for key {index:?} to {file}"))]
PrettyPrinting {
backtrace: Backtrace,
file: Utf8PathBuf,
index: DirectiveIndex,
source: io::Error,
},
}
pub struct TreeWriter {
config: Config,
}
impl TreeWriter {
pub fn new(config: Config) -> Self {
Self { config }
}
}
impl TreeWriter {
pub fn write_directives(&self, directives: Vec<Directive>) -> Result<()> {
let accounts = DashMap::<_, Vec<_>>::new();
directives
.into_par_iter()
.for_each_with(&accounts, |directives, directive| {
let index = (&directive).try_into().unwrap();
directives.entry(index).or_default().push(directive);
});
let errors = accounts
.into_par_iter()
.map(|(index, directives)| self.write_month(index, directives))
.filter_map(Result::err)
.collect::<Vec<_>>();
if errors.is_empty() {
Ok(())
} else {
Err(errors.into_iter().fold(
format_err!("encountered errors while writing directives to file tree"),
Report::error,
))
}
}
}
impl TreeWriter {
fn write_month(
&self,
index: DirectiveIndex,
mut directives: Vec<Directive>,
) -> Result<(), Error> {
directives.par_sort_by_key(Directive::date);
let file = index.file_in(&self.config.base_directory);
self.open_file(&file)
.and_then(|file| {
PrettyPrinter::<_, 2, 2, 100>::buffered(file).print_directives(&directives)
})
.context(PrettyPrintingSnafu { file, index })
}
fn open_file(&self, file_path: &Utf8Path) -> io::Result<File> {
self.ensure_directory(file_path.parent().unwrap())?;
File::create(file_path).map_err(<_>::into)
}
fn ensure_directory(&self, directory: &Utf8Path) -> io::Result<()> {
fs::create_dir_all(directory)
}
}
#[derive(Debug, Eq, Hash, PartialEq)]
struct DirectiveIndex {
account: Account,
year: i32,
month: Month,
}
impl DirectiveIndex {
fn file_in(&self, path: &Utf8Path) -> Utf8PathBuf {
let Self {
account,
year,
month,
} = self;
let month = *month as u8;
let mut path = path.to_string();
let additional = AsRef::<str>::as_ref(&account).len() + 4 + 2 + 5 + 3; // account name + year + month + extension + extra separators
path.reserve(additional);
account
.segments()
.for_each(|component| write!(path, "/{component}").unwrap());
write!(path, "/{year}/{month:02}.bean").unwrap();
path.into()
}
}
impl TryFrom<&Directive> for DirectiveIndex {
type Error = Error;
fn try_from(value: &Directive) -> Result<Self, Self::Error> {
let account = if let Some(account) = value.main_account() {
account.to_owned()
} else {
return IndexingDirectiveSnafu {
directive: value.clone(),
}
.fail();
};
let date = value.date();
let year = date.year();
let month = date.month();
Ok(Self {
account,
year,
month,
})
}
}
[package]
name = "beancount-tree-writer"
version = "0.0.0-dev.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
camino = "1.1.1"
color-eyre = "0.6.2"
itertools = "0.10.5"
rayon = "1.5.3"
time = "0.3.14"
snafu = "0.7.1"
[dependencies.beancount-pretty-printer]
path = "../beancount-pretty-printer"
[dependencies.beancount-types]
path = "../beancount-types"
[dependencies.dashmap]
version = "5.4.0"
features = ["rayon"]
name = "backtrace"
version = "0.3.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "camino"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e"
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
[[package]]
name = "color-eyre"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204"
dependencies = [
"backtrace",
"color-spantrace",
"eyre",
"indenter",
"once_cell",
"owo-colors",
"tracing-error",
]
[[package]]
name = "color-spantrace"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce"
dependencies = [
"once_cell",
"owo-colors",
"tracing-core",
"tracing-error",
]
name = "crossbeam-deque"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"once_cell",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "dashmap"
version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
dependencies = [
"cfg-if",
"hashbrown",
"lock_api",
"once_cell",
"parking_lot_core",
"rayon",
]
[[package]]
[[package]]
name = "gimli"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "indenter"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
dependencies = [
"adler",
]
[[package]]
name = "owo-colors"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "parking_lot_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
]
]
[[package]]
name = "rayon"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]]
name = "tracing"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
dependencies = [
"cfg-if",
"pin-project-lite",
"tracing-core",
]
[[package]]
name = "tracing-core"
version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-error"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
dependencies = [
"tracing",
"tracing-subscriber",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
dependencies = [
"sharded-slab",
"thread_local",
"tracing-core",
[[package]]
name = "windows-sys"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
name = "windows_x86_64_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]