add a simple writer for saving a set of directives to a tree of files

korrat
Sep 23, 2022, 11:43 AM
D6UTHZA4XNAR2PTG4YEZFNNH3OTSNOWGDSVBYDRE5R2YSV7MPN6AC

Dependencies

  • [2] MYQI5JID update dependencies
  • [3] QRIJE4AQ add a simple pretty printer for beancount directives
  • [*] I2P2FTLE add basic parser for german decimals
  • [*] YDK6X6PP add a library of important types for beancount

Change contents

  • file addition: beancount-tree-writer (d--r------)
    [5.18]
  • file addition: src (d--r------)
    [0.33]
  • file addition: lib.rs (---r------)
    [0.50]
    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,
    })
    }
    }
  • file addition: Cargo.toml (---r------)
    [0.33]
    [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"]
  • edit in Cargo.toml at line 4
    [3.5395]
    [3.5395]
    "common/beancount-tree-writer",
  • edit in Cargo.lock at line 4
    [5.10020]
    [5.10020]
    [[package]]
    name = "addr2line"
    version = "0.17.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
    dependencies = [
    "gimli",
    ]
  • edit in Cargo.lock at line 15
    [5.10033]
    [6.26307]
    name = "adler"
    version = "1.0.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
    [[package]]
  • edit in Cargo.lock at line 42
    [3.5470]
    [3.5470]
    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]]
  • edit in Cargo.lock at line 62
    [3.5582]
    [3.5582]
    ]
    [[package]]
    name = "beancount-tree-writer"
    version = "0.0.0-dev.0"
    dependencies = [
    "beancount-pretty-printer",
    "beancount-types",
    "camino",
    "color-eyre",
    "dashmap",
    "itertools",
    "rayon",
    "snafu",
    "time",
  • edit in Cargo.lock at line 125
    [6.27574]
    [6.27574]
    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]]
  • edit in Cargo.lock at line 141
    [6.27751]
    [6.27751]
    [[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",
    ]
  • edit in Cargo.lock at line 180
    [6.28031]
    [6.28031]
    ]
    [[package]]
    name = "crossbeam-channel"
    version = "0.5.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
    dependencies = [
    "cfg-if",
    "crossbeam-utils",
  • edit in Cargo.lock at line 193
    [6.28046]
    [6.28046]
    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]]
  • edit in Cargo.lock at line 257
    [6.28473]
    [6.28473]
    [[package]]
    name = "either"
    version = "1.8.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
  • edit in Cargo.lock at line 269
    [6.28671]
    [6.28671]
    [[package]]
    name = "eyre"
    version = "0.6.8"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
    dependencies = [
    "indenter",
    "once_cell",
    ]
  • edit in Cargo.lock at line 313
    [5.10524]
    [6.29337]
    [[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"
  • edit in Cargo.lock at line 331
    [6.29525]
    [5.10524]
    [[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"
  • edit in Cargo.lock at line 370
    [6.30029]
    [6.30029]
    name = "itertools"
    version = "0.10.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
    dependencies = [
    "either",
    ]
    [[package]]
  • edit in Cargo.lock at line 418
    [6.31133]
    [6.31133]
    [[package]]
    name = "lock_api"
    version = "0.4.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
    dependencies = [
    "autocfg",
    "scopeguard",
    ]
  • edit in Cargo.lock at line 434
    [6.31323]
    [6.31323]
    [[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",
    ]
  • edit in Cargo.lock at line 463
    [6.31352]
    [6.31352]
    name = "num_cpus"
    version = "1.13.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
    dependencies = [
    "hermit-abi",
    "libc",
    ]
    [[package]]
  • edit in Cargo.lock at line 482
    [6.31575]
    [6.31575]
    name = "object"
    version = "0.29.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
    dependencies = [
    "memchr",
    ]
    [[package]]
  • edit in Cargo.lock at line 495
    [2.430]
    [6.31756]
    [[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",
    ]
  • edit in Cargo.lock at line 516
    [6.31769]
    [6.31769]
    name = "pin-project-lite"
    version = "0.2.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
    [[package]]
  • edit in Cargo.lock at line 638
    [6.34242]
    [6.34242]
    ]
    [[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",
  • edit in Cargo.lock at line 721
    [6.35166]
    [6.35166]
    name = "rustc-demangle"
    version = "0.1.21"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
    [[package]]
  • edit in Cargo.lock at line 737
    [5.11712]
    [5.11712]
    [[package]]
    name = "scopeguard"
    version = "1.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
  • edit in Cargo.lock at line 751
    [6.35438]
    [6.35438]
    name = "sharded-slab"
    version = "0.1.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
    dependencies = [
    "lazy_static",
    ]
    [[package]]
  • edit in Cargo.lock at line 766
    [6.35629]
    [6.35629]
    name = "smallvec"
    version = "1.9.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
    [[package]]
  • edit in Cargo.lock at line 854
    [6.37612]
    [6.37612]
    ]
    [[package]]
    name = "thread_local"
    version = "1.1.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
    dependencies = [
    "once_cell",
  • edit in Cargo.lock at line 873
    [6.37845]
    [6.37845]
    ]
    [[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",
  • edit in Cargo.lock at line 924
    [6.37861]
    [6.37861]
    name = "valuable"
    version = "0.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
    [[package]]
  • edit in Cargo.lock at line 971
    [6.39176]
    [6.39176]
    [[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"
  • edit in Cargo.lock at line 1004
    [6.39189]
    [6.39189]
    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]]