Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hledger print #13

Merged
merged 3 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use thiserror::Error;
#[derive(Debug, Error)]
pub enum ImportError {
#[error("Failed to interact with hledger: {0}")]
HledgerExection(#[from] std::io::Error),
HledgerExecution(#[from] std::io::Error),
#[error("Encoding or conversion error: {0}")]
StringConversion(#[from] std::str::Utf8Error),
#[error("Failed to provide the path to the configruation file. Please provide the path to the configuration file in the environment variable \"HLEDGER_IMPORT_CONFIG\" to fix this error.")]
Expand Down
2 changes: 1 addition & 1 deletion src/hledger/deduplication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub fn get_hledger_codes(config: &HledgerConfig) -> Result<HashSet<String>> {
let output = Command::new(&config.path).arg("codes").output();
let output = match output {
Ok(o) => o,
Err(e) => return Err(ImportError::HledgerExection(e)),
Err(e) => return Err(ImportError::HledgerExecution(e)),
};

let codes = match std::str::from_utf8(&output.stdout) {
Expand Down
32 changes: 32 additions & 0 deletions src/hledger/format.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::io::{Read, Write};
use std::process::{Command, Stdio};

use crate::{config::HledgerConfig, error::*};

pub fn hledger_format(config: &HledgerConfig, transactions: &str) -> Result<String> {
let mut process = Command::new(&config.path)
.arg("print")
.arg("-x")
.arg("-f-")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.map_err(ImportError::HledgerExecution)?;

if let Some(mut stdin) = process.stdin.take() {
stdin
.write_all(transactions.as_bytes())
.map_err(ImportError::HledgerExecution)?;
}

let mut output = String::new();
if let Some(mut stdout) = process.stdout.take() {
stdout
.read_to_string(&mut output)
.map_err(ImportError::HledgerExecution)?;
}

process.wait().map_err(ImportError::HledgerExecution)?;

Ok(output)
}
1 change: 1 addition & 0 deletions src/hledger/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod deduplication;
pub mod format;
pub mod output;
pub mod query;
33 changes: 17 additions & 16 deletions src/hledger/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,10 @@ impl Display for Transaction {
result = format!("{} | {}", &result, note);
}
if let Some(comment) = &self.comment {
result = format!("{}\n ; {}", &result, comment);
result = format!("{}\n ; {}", &result, comment);
}
self.tags.iter().for_each(|tag| {
result = format!("{}\n ; {}", &result, tag);
result = format!("{}\n ; {}", &result, tag);
});
self.postings.iter().for_each(|p| {
result = format!("{}\n{}", &result, p);
Expand All @@ -178,17 +178,15 @@ impl Display for Posting {
let mut render = match &self.amount {
Some(amount) => {
let amount = amount.to_string();
// 80 is the default line length - the amount should be aligned to the right (at position 80)
let length_filler = 80 - 2 - amount.len() - 1;
format!(" {:<w$} {}", &self.account, &amount, w = length_filler)
format!(" {} {}", &self.account, &amount)
}
None => format!(" {}", &self.account),
None => format!(" {}", &self.account),
};
if let Some(comment) = &self.comment {
render = format!("{}\n ; {}", &render, comment);
render = format!("{}\n ; {}", &render, comment);
}
self.tags.iter().for_each(|tag| {
render = format!("{}\n ; {}", &render, tag);
render = format!("{}\n ; {}", &render, tag);
});
write!(f, "{}", &render)
}
Expand All @@ -205,7 +203,7 @@ impl<'a> HeaderComment<'a> {
}
}

impl<'a> Display for HeaderComment<'a> {
impl Display for HeaderComment<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let asterisk_line: String = "*".repeat(78);
let date_time = chrono::Local::now().to_rfc2822();
Expand Down Expand Up @@ -318,7 +316,10 @@ mod tests {
],
};
let result = posting.to_string();
assert_eq!(result, " Assets:Cash -11,44 EUR\n ; lunch:\n ; valuation: 2024-05-02");
assert_eq!(
result,
" Assets:Cash -11,44 EUR\n ; lunch:\n ; valuation: 2024-05-02"
);

let posting = Posting {
account: String::from("Expenses:Groceries"),
Expand All @@ -327,7 +328,7 @@ mod tests {
tags: vec![],
};
let result = posting.to_string();
assert_eq!(result, " Expenses:Groceries");
assert_eq!(result, " Expenses:Groceries");

let posting = Posting {
account: String::from("Expenses:Groceries"),
Expand All @@ -336,7 +337,7 @@ mod tests {
tags: vec![],
};
let result = posting.to_string();
assert_eq!(result, " Expenses:Groceries\n ; test comment");
assert_eq!(result, " Expenses:Groceries\n ; test comment");
}

#[test]
Expand All @@ -352,7 +353,7 @@ mod tests {
postings: vec![],
};
let result = t.to_string();
assert_eq!(result, "2024-11-22 * (ABC123) Test | Note\n ; comment");
assert_eq!(result, "2024-11-22 * (ABC123) Test | Note\n ; comment");

let t = Transaction {
date: NaiveDate::from_ymd_opt(2024, 11, 22).unwrap(),
Expand All @@ -370,7 +371,7 @@ mod tests {
let result = t.to_string();
assert_eq!(
result,
"2024-11-22 * (ABC123) Test | Note\n ; comment\n ; lunch:\n ; foo: bar"
"2024-11-22 * (ABC123) Test | Note\n ; comment\n ; lunch:\n ; foo: bar"
);

let t = Transaction {
Expand Down Expand Up @@ -416,7 +417,7 @@ mod tests {
],
};
let result = t.to_string();
assert_eq!(result, "2020-06-18 * (123-XYZ-321) Store | Bought something\n ; this is a test\n Assets:Cash -2.799,97 EUR\n Expenses:Test\n ; Some test");
assert_eq!(result, "2020-06-18 * (123-XYZ-321) Store | Bought something\n ; this is a test\n Assets:Cash -2.799,97 EUR\n Expenses:Test\n ; Some test");

let t = Transaction {
date: NaiveDate::from_ymd_opt(2020, 6, 18).unwrap(),
Expand Down Expand Up @@ -445,7 +446,7 @@ mod tests {
],
};
let result = t.to_string();
assert_eq!(result, "2020-06-18 * Store | Bought something\n ; this is a test\n Assets:Cash -2.799,97 EUR\n Expenses:Test\n ; Some test");
assert_eq!(result, "2020-06-18 * Store | Bought something\n ; this is a test\n Assets:Cash -2.799,97 EUR\n Expenses:Test\n ; Some test");
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion src/hledger/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ pub fn query_hledger_by_payee_and_account(

let output = match output {
Ok(o) => o,
Err(e) => return Err(ImportError::HledgerExection(e)),
Err(e) => return Err(ImportError::HledgerExecution(e)),
};

let json_str = match std::str::from_utf8(&output.stdout) {
Expand Down
6 changes: 3 additions & 3 deletions src/importers/flatex_inv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ impl<'a> FlatexPdfRegexMatcher<'a> {
}
}

impl<'a> TryInto<NaiveDate> for FlatexPdfRegexMatcher<'a> {
impl TryInto<NaiveDate> for FlatexPdfRegexMatcher<'_> {
type Error = ImportError;

fn try_into(self) -> std::prelude::v1::Result<NaiveDate, Self::Error> {
Expand All @@ -259,7 +259,7 @@ impl<'a> TryInto<NaiveDate> for FlatexPdfRegexMatcher<'a> {
}
}

impl<'a> TryInto<AmountAndCommodity> for FlatexPdfRegexMatcher<'a> {
impl TryInto<AmountAndCommodity> for FlatexPdfRegexMatcher<'_> {
type Error = ImportError;

fn try_into(self) -> std::prelude::v1::Result<AmountAndCommodity, Self::Error> {
Expand Down Expand Up @@ -299,7 +299,7 @@ impl<'a> TryInto<AmountAndCommodity> for FlatexPdfRegexMatcher<'a> {
}
}

impl<'a> TryInto<BigDecimal> for FlatexPdfRegexMatcher<'a> {
impl TryInto<BigDecimal> for FlatexPdfRegexMatcher<'_> {
type Error = ImportError;

fn try_into(self) -> std::prelude::v1::Result<BigDecimal, Self::Error> {
Expand Down
15 changes: 13 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::hledger::output::Transaction;
use clap::{command, Parser, ValueEnum};
use config::ImporterConfig;
use error::Result;
use hledger::output::HeaderComment;
use hledger::{format::hledger_format, output::HeaderComment};

pub mod config;
pub mod error;
Expand Down Expand Up @@ -108,8 +108,19 @@ fn main() {
let importer: Box<dyn HledgerImporter> = args.file_type.into();
match importer.parse(&args.input_file, &config, &codes) {
Ok(transactions) => {
let transactions: Vec<String> = transactions.iter().map(|t| t.to_string()).collect();
let transactions = transactions.join("\n");

let transactions = match hledger_format(&config.hledger, &transactions) {
Ok(t) => t,
Err(e) => {
eprintln!("[ERROR] {}", e);
return;
}
};

println!("{}", HeaderComment::new(importer.output_title()));
transactions.iter().for_each(|t| println!("{}\n", t));
println!("{}", transactions);
println!();
}
Err(e) => {
Expand Down
Loading