Find the data root via the XDG config directory
Running the tool from anywhere required either a --root flag or an exported MONEY_ROOT. Read the data root from $XDG_CONFIG_HOME/money/config.toml (~/.config/money/config.toml) instead, so it can be configured once. Resolution order is --root, then $MONEY_ROOT, then the config file, then ~/money. A leading tilde in the config file is expanded, since no shell has done it for us, and relative paths are made absolute. The new "money config" subcommand prints the resolved root and which rule chose it, which is the first thing to check when the tool reads the wrong directory. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+33
-10
@@ -9,7 +9,6 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
@@ -35,8 +34,10 @@ commands:
|
||||
report spending by tag
|
||||
accounts list accounts with balances
|
||||
parsers list available statement parsers
|
||||
config show which data root is in use and why
|
||||
|
||||
The data root defaults to $MONEY_ROOT, or ~/money if that is unset.
|
||||
The data root is taken from --root, else $MONEY_ROOT, else the "root" key in
|
||||
$XDG_CONFIG_HOME/money/config.toml (~/.config/money/config.toml), else ~/money.
|
||||
`
|
||||
|
||||
func main() {
|
||||
@@ -47,7 +48,7 @@ func main() {
|
||||
}
|
||||
|
||||
func run(args []string) error {
|
||||
root := defaultRoot()
|
||||
var root string // empty means "not given on the command line"
|
||||
// A leading --root/-root applies to every subcommand.
|
||||
for len(args) > 0 && strings.HasPrefix(args[0], "-") {
|
||||
flagName := strings.TrimLeft(args[0], "-")
|
||||
@@ -75,12 +76,14 @@ func run(args []string) error {
|
||||
cmd, args = args[0], args[1:]
|
||||
}
|
||||
|
||||
abs, err := filepath.Abs(root)
|
||||
abs, source, err := config.ResolveRoot(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch cmd {
|
||||
case "config":
|
||||
return cmdConfig(abs, source)
|
||||
case "import":
|
||||
return cmdImport(abs, args)
|
||||
case "retag":
|
||||
@@ -104,14 +107,34 @@ func run(args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
func defaultRoot() string {
|
||||
if r := os.Getenv("MONEY_ROOT"); r != "" {
|
||||
return r
|
||||
// cmdConfig explains which data root is in use and where that came from,
|
||||
// which is the first thing to check when the tool looks at the wrong place.
|
||||
func cmdConfig(root string, source config.RootSource) error {
|
||||
path, err := config.UserConfigPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if home, err := os.UserHomeDir(); err == nil {
|
||||
return filepath.Join(home, "money")
|
||||
exists := "not present"
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
exists = "present"
|
||||
}
|
||||
return "."
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "data root\t%s\n", root)
|
||||
fmt.Fprintf(w, "chosen by\t%s\n", source)
|
||||
fmt.Fprintf(w, "config file\t%s (%s)\n", path, exists)
|
||||
if _, err := os.Stat(root); err != nil {
|
||||
fmt.Fprintf(w, "status\tdoes not exist yet\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "index\t%s\n", config.IndexPath(root))
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
if source != config.RootFromConfig && exists == "not present" {
|
||||
fmt.Printf("\nTo point money at a different directory, create %s with:\n\n root = %q\n",
|
||||
path, root)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// open loads the config and index that every command needs.
|
||||
|
||||
Reference in New Issue
Block a user