feat: add inline and block runner. Improve execution error handling

This commit is contained in:
Justin Lin committed 2025-07-25 12:23:47 +10:00
1 parent 8f764548b9
commit a2c99c710e
6 files changed
+218 -63

No files matched your search

+72
View File
@@ -0,0 +1,72 @@
; -*- ledger -*-
; This example file retrived from ledger-cli.org example journal file
; https://ledger-cli.org/doc/ledger3.html#Example-Journal-File
= /^Income/
(Liabilities:Tithe) 0.12
~ Monthly
Assets:Checking $500.00
Income:Salary
~ Monthly
Expenses:Food $100
Assets
2010/12/01 * Checking balance
Assets:Checking $1,000.00
Equity:Opening Balances
2010/12/20 * Organic Co-op
Expenses:Food:Groceries $ 37.50 ; [=2011/01/01]
Expenses:Food:Groceries $ 37.50 ; [=2011/02/01]
Expenses:Food:Groceries $ 37.50 ; [=2011/03/01]
Expenses:Food:Groceries $ 37.50 ; [=2011/04/01]
Expenses:Food:Groceries $ 37.50 ; [=2011/05/01]
Expenses:Food:Groceries $ 37.50 ; [=2011/06/01]
Assets:Checking $ -225.00
2010/12/28=2011/01/01 Acme Mortgage
Liabilities:Mortgage:Principal $ 200.00
Expenses:Interest:Mortgage $ 500.00
Expenses:Escrow $ 300.00
Assets:Checking $ -1000.00
2011/01/02 Grocery Store
Expenses:Food:Groceries $ 65.00
Assets:Checking
2011/01/05 Employer
Assets:Checking $ 2000.00
Income:Salary
2011/01/14 Bank
; Regular monthly savings transfer
Assets:Savings $ 300.00
Assets:Checking
2011/01/19 Grocery Store
Expenses:Food:Groceries $ 44.00 ; hastag: not block
Assets:Checking
2011/01/25 Bank
; Transfer to cover car purchase
Assets:Checking $ 5,500.00
Assets:Savings
; :nobudget:
apply tag hastag: true
apply tag nestedtag: true
2011/01/25 Tom's Used Cars
Expenses:Auto $ 5,500.00
; :nobudget:
Assets:Checking
2011/01/27 Book Store
Expenses:Books $20.00
Liabilities:MasterCard
end tag
2011/12/01 Sale
Assets:Checking:Business $ 30.00
Income:Sales
end tag
+109
View File
@@ -0,0 +1,109 @@
# Finance Report from 2011-01 to 2011-02
## Previous status:
```
Balance Sheet 2010-12-31
|| 2010-12-31
================================++============
Assets ||
--------------------------------++------------
Assets:Checking || $-225.00
--------------------------------++------------
|| $-225.00
================================++============
Liabilities ||
--------------------------------++------------
Liabilities:Mortgage:Principal || $-200.00
--------------------------------++------------
|| $-200.00
================================++============
Net: || $-25.00
```
## Expenses:
### Expense Summary by Category
```
Budget performance in 2011-01:
|| Jan
===============++==============================
Expenses || $5,629.00
Expenses:Food || $109.00 [ 109% of $100.00]
---------------++------------------------------
|| $5,629.00 [5629% of $100.00]
```
```
$5,500.00 Expenses:Auto
$109.00 Expenses:Food
$20.00 Expenses:Books
--------------------
$5,629.00
```
## Net Income:
```
Income Statement 2011-01
|| Jan
=========================++============
Revenues ||
-------------------------++------------
Income:Salary || $2,000.00
-------------------------++------------
|| $2,000.00
=========================++============
Expenses ||
-------------------------++------------
Expenses:Auto || $5,500.00
Expenses:Books || $20.00
Expenses:Food:Groceries || $109.00
-------------------------++------------
|| $5,629.00
=========================++============
Net: || $-3,629.00
```
## Ending balance:
```
Balance Sheet 2011-01-31
|| 2011-01-31
================================++============
Assets ||
--------------------------------++------------
Assets:Checking || $1,366.00
Assets:Savings || $-5,200.00
--------------------------------++------------
|| $-3,834.00
================================++============
Liabilities ||
--------------------------------++------------
Liabilities:MasterCard || $20.00
Liabilities:Mortgage:Principal || $-200.00
--------------------------------++------------
|| $-180.00
================================++============
Net: || $-3,654.00
```
-45
View File
@@ -1,45 +0,0 @@
---
output: "reports_{{.b}}.md"
params:
b:
required: true
usage: |
Required.
The begin time of report.
Examples:
2025
2025-07
2025-07-15
Jul
e:
required: true
usage: |
Required.
The end time of report.
Same format as -b
f:
default: ~/.hledger.journal
usage: The ledger file to parse
---
# Finance Report from {{.b}} to {{.e}}
## Previous status:
{{ sh "hledger -f $f balancesheet -e $b" }}
## Expenses:
### Expense Summary by Category
{{ sh "hledger -f $f bal expenses -b $b -e $e --depth 3 --sort amount" }}
{{ sh "hledger -f $f bal expenses -b $b -e $e --depth 2 --sort amount" }}
## Net Income:
{{sh "hledger -f $f income -b $b -e $e --monthly"}}
## Ending balance:
{{sh "hledger -f $f balancesheet -e $e"}}
+1 -1
View File
@@ -23,7 +23,7 @@ func parseDocument(doc string) (frontmatter string, body string, err error) {
err = fmt.Errorf("Invalid document: frontmatter required.\n%s", doc)
return
}
parts := strings.Split(doc, sep)
parts := strings.SplitN(doc, sep, 3)
if len(parts) < 3 {
err = fmt.Errorf("Invalid document: frontmatter required.\n%s", doc)
return
+2 -17
View File
@@ -2,28 +2,13 @@ package main
import (
"bytes"
"fmt"
"os/exec"
"text/template"
)
func sh(ctx TemplateContext) func(string) string {
return func(command string) string {
cmd := exec.Command("sh", "-c", command)
for k, v := range ctx {
cmd.Env = append(cmd.Env, k+"="+v)
}
out, err := cmd.Output()
if err != nil {
return fmt.Sprintf("> Failed to execute the command: %s\n> %s\n", cmd.Args, err.Error())
}
return fmt.Sprintf("\n```\n%s\n```\n", string(out))
}
}
func render(tmpl string, ctx TemplateContext) []byte {
funcMap := template.FuncMap{
"sh": sh(ctx),
"sh": ctx.inline,
"shell": ctx.codeBlock,
}
t, err := template.New("foo").Funcs(funcMap).Parse(tmpl)
if err != nil {
+34
View File
@@ -3,7 +3,10 @@ package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"os/exec"
"strings"
"text/template"
)
@@ -40,3 +43,34 @@ type ParamSpec struct {
}
type TemplateContext map[string]string
func (ctx TemplateContext) run(command string) (string, error) {
cmd := exec.Command("sh", "-c", command)
var stdout bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stdout
for k, v := range ctx {
cmd.Env = append(cmd.Env, k+"="+v)
}
err := cmd.Run()
if err != nil {
return "", errors.New(stdout.String())
}
return stdout.String(), nil
}
func (ctx TemplateContext) codeBlock(command string) string {
out, err := ctx.run(command)
if err != nil {
return fmt.Sprintf("> Failed to execute the command:\n> `%s`\n> %s\n", command, err.Error())
}
return fmt.Sprintf("\n```\n%s\n```\n", out)
}
func (ctx TemplateContext) inline(command string) string {
out, err := ctx.run(command)
if err != nil {
return fmt.Sprintf("`Failed to execute the command: '%s'. %s`", command, err.Error())
}
return fmt.Sprintf("`%s`", strings.Trim(out, "\n "))
}