From 9c30c960d08b9fdd7138dbb000f2932be5f79021 Mon Sep 17 00:00:00 2001 From: Chris Waldon Date: Thu, 24 Nov 2022 08:09:02 -0500 Subject: [PATCH] cmd/rosebus,deps: create new main pkg This commit starts over on the main package, focusing on usability by regular people. This commit adds just the flow to open a ledger file, but includes backing that file up to a cache directory as a precaution before doing any manipulation on it. Signed-off-by: Chris Waldon --- cmd/rosebud/main.go | 150 ++++++++++++++++++++++++++++++++++++++++++++ go.mod | 3 + go.sum | 6 ++ 3 files changed, 159 insertions(+) create mode 100644 cmd/rosebud/main.go diff --git a/cmd/rosebud/main.go b/cmd/rosebud/main.go new file mode 100644 index 0000000..8ee8e1b --- /dev/null +++ b/cmd/rosebud/main.go @@ -0,0 +1,150 @@ +package main + +import ( + "fmt" + "io" + "log" + "os" + "path/filepath" + "time" + + "gioui.org/app" + "gioui.org/io/system" + "gioui.org/layout" + "gioui.org/op" + "gioui.org/x/explorer" + "git.sr.ht/~gioverse/skel/bus" + "git.sr.ht/~gioverse/skel/future" + "git.sr.ht/~gioverse/skel/window" + "github.com/howeyc/ledger" +) + +func main() { + go func() { + bus := bus.New() + windower := window.NewWindower(bus) + window.NewWindowForBus(bus, loop, app.Title("Rosebud - tend to your finances")) + windower.Run() + os.Exit(0) + }() + app.Main() +} + +type LoadStage byte + +const ( + RequestingFiles LoadStage = iota + LoadingFiles + Ready +) + +func loop(w *app.Window, conn bus.Connection) error { + var ops op.Ops + ui := UI{ + Explorer: explorer.NewExplorer(w), + Conn: conn, + } + for { + select { + case e := <-conn.Output(): + if future.TryResults(e) { + w.Invalidate() + } + case e := <-w.Events(): + ui.Explorer.ListenEvents(e) + switch e := e.(type) { + case system.DestroyEvent: + if e.Err != nil { + log.Println("error: %v", e.Err) + } + return e.Err + case system.FrameEvent: + gtx := layout.NewContext(&ops, e) + ui.Layout(gtx) + e.Frame(gtx.Ops) + } + } + } +} + +type UI struct { + Stage LoadStage + Explorer *explorer.Explorer + Conn bus.Connection +} + +type ( + C = layout.Context + D = layout.Dimensions +) + +type Namer interface { + Name() string +} + +func (ui *UI) Layout(gtx C) D { + type LoadInfo struct { + Txs []*ledger.Transaction + OutFilePath string + CacheFilePath string + } + switch ui.Stage { + case RequestingFiles: + future.Run(ui.Conn, + func() (li LoadInfo, err error) { + cacheDir, err := os.UserCacheDir() + if err != nil { + return LoadInfo{}, fmt.Errorf("unable to resolve cache dir: %w", err) + } + confDir, err := os.UserConfigDir() + if err != nil { + return LoadInfo{}, fmt.Errorf("unable to resolve config dir: %w", err) + } + cacheDir = filepath.Join(cacheDir, "rosebud") + if err := os.MkdirAll(cacheDir, 0o755); err != nil { + return LoadInfo{}, fmt.Errorf("unable to make application cache dir: %w", err) + } + file, err := ui.Explorer.ChooseFile("txt", "ledger") + if err != nil { + return LoadInfo{}, err + } + outFilePath := filepath.Join(confDir, "rosebud", "budget.ledger") + cacheFileName := "file" + if namer, ok := file.(Namer); ok { + name := namer.Name() + outFilePath = name + cacheFileName = filepath.Base(name) + } + + defer file.Close() + cacheFileName = fmt.Sprintf("%s-%s.gz", time.Now().Local().Format(time.RFC3339), cacheFileName) + cacheFilePath := filepath.Join(cacheDir, cacheFileName) + backupFile, err := os.Create(cacheFilePath) + if err != nil { + return LoadInfo{}, fmt.Errorf("unable to create backup file: %w", err) + } + defer func() { + closeErr := backupFile.Close() + if closeErr != nil && err == nil { + err = fmt.Errorf("failed closing backup file: %w", closeErr) + } + }() + tee := io.TeeReader(file, backupFile) + transactions, err := ledger.ParseLedger(tee) + if err != nil { + return LoadInfo{}, fmt.Errorf("failed parsing input file: %w", err) + } + return LoadInfo{ + Txs: transactions, + OutFilePath: outFilePath, + CacheFilePath: cacheFilePath, + }, nil + }, + func(li LoadInfo, err error) bool { + log.Printf("%v, %v", li, err) + return true + }) + ui.Stage = LoadingFiles + } + return D{} +} diff --git a/go.mod b/go.mod index 2544513..2e8c76a 100644 --- a/go.mod +++ b/go.mod @@ -5,15 +5,18 @@ go 1.19 require ( gioui.org v0.0.0-20221122135904-dee53b364560 gioui.org/x v0.0.0-20221121204253-9da08d942944 + git.sr.ht/~gioverse/skel v0.0.0-20220916150537-2f38f089e413 github.com/howeyc/ledger v0.3.5 ) require ( gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 // indirect gioui.org/shader v1.0.6 // indirect + git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 // indirect github.com/benoitkugler/textlayout v0.1.3 // indirect github.com/gioui/uax v0.2.1-0.20220819135011-cda973fac06d // indirect github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b // indirect + github.com/godbus/dbus/v5 v5.0.6 // indirect github.com/joyt/godate v0.0.0-20150226210126-7151572574a7 // indirect github.com/marcmak/calc v0.0.0-20150509200512-5bbbfc3b3149 // indirect golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 // indirect diff --git a/go.sum b/go.sum index 864f202..35c7c46 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,10 @@ gioui.org/shader v1.0.6 h1:cvZmU+eODFR2545X+/8XucgZdTtEjR3QWW6W65b0q5Y= gioui.org/shader v1.0.6/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= gioui.org/x v0.0.0-20221121204253-9da08d942944 h1:1qB+TI3FwPFWzyqF6LzW4jhC3Vc+LbBnMqV7EvmJflI= gioui.org/x v0.0.0-20221121204253-9da08d942944/go.mod h1:uhVlN625ysZfFEbEdxt+wgyCGW2sh5p6SYs9dr+w+u4= +git.sr.ht/~gioverse/skel v0.0.0-20220916150537-2f38f089e413 h1:rqEp9NqS0icb0xxSWpUe11sHf0bhwobxd+O6Wei6wGc= +git.sr.ht/~gioverse/skel v0.0.0-20220916150537-2f38f089e413/go.mod h1:DtJGzJPf/ONJskXDaxORcVjIFpKWN7mBq0R8j7c4BQM= +git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr9PPB5aw8SjcOWWila7ZI= +git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0/go.mod h1:+axXBRUTIDlCeE73IKeD/os7LoEnTKdkp8/gQOFjqyo= github.com/benoitkugler/pstokenizer v1.0.0/go.mod h1:l1G2Voirz0q/jj0TQfabNxVsa8HZXh/VMxFSRALWTiE= github.com/benoitkugler/textlayout v0.0.5/go.mod h1:puH4v13Uz7uIhIH0XMk5jgc8U3MXcn5r3VlV9K8n0D8= github.com/benoitkugler/textlayout v0.1.3 h1:Jv0E28xDkke3KrWle90yOLtBmZsUqXLBy70lZRfbKN0= @@ -17,6 +21,8 @@ github.com/gioui/uax v0.2.1-0.20220819135011-cda973fac06d h1:ro1W5kY1pVBLHy4GokZ github.com/gioui/uax v0.2.1-0.20220819135011-cda973fac06d/go.mod h1:b6uGh9ySJPVQG/RdiI88bE5sUGDk6vzzRujv1BAeuJc= github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b h1:WINlj3ANt+CVrO2B4NGDHRlPvEWZPxjhb7z+JKypwXI= github.com/go-text/typesetting v0.0.0-20220411150340-35994bc27a7b/go.mod h1:ZNYu5saGoMOqtkVH5T8onTwhzenDUVszI+5WFHJRaxQ= +github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/howeyc/ledger v0.3.5 h1:9EfDs73TzUUeK9W5spgAR1ELW5Ywd9lbd6ha25sgDf0= github.com/howeyc/ledger v0.3.5/go.mod h1:Bt65DBbqSGABPEugJXzcbH1KOi3QBjIk/v6/AtoTkcM= github.com/joyt/godate v0.0.0-20150226210126-7151572574a7 h1:2wH5antjhmU3EuWyidm0lJ4B9hGMpl5lNRo+M9uGJ5A= -- 2.45.2