Skip to content

Commit 93388ff

Browse files
author
louie
committed
cli app
1 parent d679f42 commit 93388ff

File tree

6 files changed

+140
-1
lines changed

6 files changed

+140
-1
lines changed

NetCash.sln

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "examples\Example
1111
EndProject
1212
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "docs", "docs\docs.fsproj", "{E124CA77-2939-473A-8F36-11D24192B4A3}"
1313
EndProject
14+
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "NetCash.CLI", "src\NetCash.CLI\NetCash.CLI.fsproj", "{E22683C7-342E-4CEA-9F49-87CAE8C2D09C}"
15+
EndProject
1416
Global
1517
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1618
Debug|Any CPU = Debug|Any CPU
@@ -33,6 +35,10 @@ Global
3335
{E124CA77-2939-473A-8F36-11D24192B4A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
3436
{E124CA77-2939-473A-8F36-11D24192B4A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
3537
{E124CA77-2939-473A-8F36-11D24192B4A3}.Release|Any CPU.Build.0 = Release|Any CPU
38+
{E22683C7-342E-4CEA-9F49-87CAE8C2D09C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39+
{E22683C7-342E-4CEA-9F49-87CAE8C2D09C}.Debug|Any CPU.Build.0 = Debug|Any CPU
40+
{E22683C7-342E-4CEA-9F49-87CAE8C2D09C}.Release|Any CPU.ActiveCfg = Release|Any CPU
41+
{E22683C7-342E-4CEA-9F49-87CAE8C2D09C}.Release|Any CPU.Build.0 = Release|Any CPU
3642
EndGlobalSection
3743
GlobalSection(SolutionProperties) = preSolution
3844
HideSolutionNode = FALSE

src/NetCash.CLI/NetCash.CLI.fsproj

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<AssemblyName>netcash-cli</AssemblyName>
6+
<TargetFramework>net6.0</TargetFramework>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<Compile Include="Program.fs" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<ProjectReference Include="..\NetCash.Core\NetCash.Core.fsproj" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<PackageReference Include="Argu" Version="6.1.1" />
19+
</ItemGroup>
20+
21+
</Project>

src/NetCash.CLI/Program.fs

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
open System
2+
3+
open Argu
4+
5+
open NetCash
6+
7+
type BalArguments =
8+
| [<Unique; AltCommandLine("-l")>] Flat
9+
| [<Unique; AltCommandLine("-t")>] Tree
10+
| [<Unique; AltCommandLine("-e")>] End of string
11+
| [<MainCommand; ExactlyOnce; Last>] Book of uri: string
12+
13+
interface IArgParserTemplate with
14+
member s.Usage =
15+
match s with
16+
| Flat -> "show accounts as a flat list (default). Amounts exclude subaccount amounts."
17+
| Tree -> "show accounts as a tree. Amounts include subaccount amounts."
18+
| End _ -> "show balance before this date. A valid date string or \"today\""
19+
| Book uri -> "URI to the book."
20+
21+
[<CliPrefix(CliPrefix.DoubleDash)>]
22+
type CliArguments =
23+
| [<CustomCommandLine("bal", "balance")>] Bal of ParseResults<BalArguments>
24+
25+
interface IArgParserTemplate with
26+
member s.Usage =
27+
match s with
28+
| Bal _ -> "Show accounts and their balances."
29+
30+
module CmdHandlers =
31+
let bal uri tree endDate =
32+
use book = Book.OpenRead uri
33+
34+
let filter: seq<Account> -> seq<Account> = Seq.filter (fun acc -> not acc.Hidden)
35+
36+
let inline printBal (acc: Account) =
37+
let balance =
38+
match endDate with
39+
// TODO: replace with --current (consistent with ledger-cli)
40+
// --current
41+
// -c
42+
// Display only transactions on or before the current date.
43+
44+
| Some "today" -> acc.GetBalanceBeforeDate(DateTime.Now, tree)
45+
| Some input ->
46+
match DateTime.TryParse input with
47+
| false, _ -> failwithf "Invalid end date: %s" input
48+
| _, date -> acc.GetBalanceBeforeDate(date, tree)
49+
| _ -> acc.GetFutureBalance(tree)
50+
51+
Helpers.UI.FormatAmount(balance, acc.Currency, true)
52+
53+
let rec collectTree level (root: Account) =
54+
seq {
55+
if level > -1 then
56+
(printBal root, (String.replicate level " ") + root.Name)
57+
58+
yield!
59+
root.Children
60+
|> filter
61+
|> Seq.sortBy (fun x -> x.Name)
62+
|> Seq.collect (collectTree (level + 1))
63+
}
64+
65+
let inline collectList () =
66+
book.Accounts
67+
|> filter
68+
|> Seq.sortBy (fun x -> x.FullName)
69+
|> Seq.map (fun acc -> (printBal acc, acc.FullName))
70+
71+
let rows =
72+
if tree then
73+
collectTree -1 book.RootAccount
74+
else
75+
collectList ()
76+
|> Seq.cache
77+
78+
let rowFmt =
79+
let padding = 8
80+
let maxBalWidth = rows |> ((Seq.map (fst >> String.length)) >> Seq.max)
81+
sprintf "{0,%d} {1}" (maxBalWidth + padding)
82+
83+
for balance, fullName in rows do
84+
stdout.WriteLine(rowFmt, balance, fullName)
85+
86+
[<EntryPoint>]
87+
let main argv =
88+
GnuCashEngine.Initialize()
89+
Logging.Config(Logging.LogLevel.WARN, [| Logging.Appender.console |])
90+
91+
let cliParser = ArgumentParser.Create<CliArguments>()
92+
93+
try
94+
let results = cliParser.ParseCommandLine(inputs = argv, raiseOnUsage = true)
95+
96+
match results.GetSubCommand() with
97+
| Bal args ->
98+
let tree = args.Contains BalArguments.Tree
99+
100+
let endDate =
101+
args.TryGetResult BalArguments.End |> Option.map (fun x -> x.ToLowerInvariant())
102+
103+
let uri = args.GetResult BalArguments.Book |> GnuCashUri.Parse
104+
CmdHandlers.bal uri tree endDate
105+
with e ->
106+
stdout.WriteLine e.Message
107+
108+
0

src/NetCash.Core/Assembly.fs

+1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
open System.Runtime.CompilerServices
44

55
[<InternalsVisibleTo("NetCash.Tests")>]
6+
[<InternalsVisibleTo("netcash-cli")>]
67
()

src/NetCash.Core/Book.fs

+3
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,9 @@ type Book internal (session: nativeint) =
222222
/// Gets all accounts in this book.
223223
member self.Accounts = self.RootAccount.Descendants
224224

225+
/// Gets all top-level accounts in this book.
226+
member self.ToplevelAccounts = self.RootAccount.Children
227+
225228
/// <summary>Deletes an account.</summary>
226229
/// <remarks><list type="bullet">
227230
/// <item><description>The underlying native resource gets destroyed after this operation, although the managed Account object is still accessible, it becomes invalid, any usage afterwards would get unexpected result.</description></item>

src/NetCash.Core/Helpers.fs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ module UI =
1313
let printInfo =
1414
Bindings.gnc_commodity_print_info (GnuCashObject.nativeHandle currency, showSymbol)
1515

16-
Bindings.gnc_print_amount_with_bidi_ltr_isolate (amount, printInfo)
16+
Bindings.xaccPrintAmount (amount, printInfo)
1717
|> Bindings.g_strdup
1818
|> String.fromOwned
1919

0 commit comments

Comments
 (0)