From 956fc762166f4f6f76d67d0f821a2d32db00df5c Mon Sep 17 00:00:00 2001 From: beatinaniwa Date: Mon, 30 Mar 2026 01:58:25 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E8=A8=AD=E5=AE=9A=E3=83=87=E3=82=A3?= =?UTF-8?q?=E3=83=AC=E3=82=AF=E3=83=88=E3=83=AA=E3=82=92XDG=20Base=20Direc?= =?UTF-8?q?tory=E6=BA=96=E6=8B=A0=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit os.UserConfigDir()(macOSでは~/Library/Application Support)から ~/.config/mf-cli をデフォルトに変更し、XDG_CONFIG_HOME環境変数も サポート。Windowsでは従来通り%AppData%を使用。 - resolveConfigDir()をXDG準拠に書き換え - 相対パスのXDG_CONFIG_HOMEを無視(XDG仕様準拠) - テスト追加(XDG、デフォルトフォールバック、相対パス無視) - READMEの設定パス説明を更新 - LICENSEのcopyright年号を2026に修正 --- LICENSE | 2 +- README.md | 17 +++++----- internal/config/config.go | 15 +++++++-- internal/config/config_test.go | 58 ++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 12 deletions(-) diff --git a/LICENSE b/LICENSE index 272e67a..933b6af 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 beatinaniwa +Copyright (c) 2026 beatinaniwa Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 86764a8..f01c1f9 100644 --- a/README.md +++ b/README.md @@ -189,15 +189,14 @@ mf journals create --json '{"..."}' --dry-run ### 設定ファイル -設定ファイルの保存場所は OS の `UserConfigDir` に基づきます: - -| OS | パス | -|----|------| -| macOS | `~/Library/Application Support/mf-cli/` | -| Linux | `~/.config/mf-cli/` | -| Windows | `%AppData%\mf-cli\` | - -`MF_CONFIG_DIR` 環境変数でオーバーライドできます。 +設定ファイルの保存場所は [XDG Base Directory](https://specifications.freedesktop.org/basedir-spec/latest/) に準拠します: + +| 条件 | パス | +|------|------| +| `MF_CONFIG_DIR` 設定時 | `$MF_CONFIG_DIR/` | +| `XDG_CONFIG_HOME` 設定時 | `$XDG_CONFIG_HOME/mf-cli/` | +| デフォルト(macOS/Linux) | `~/.config/mf-cli/` | +| デフォルト(Windows) | `%AppData%\mf-cli\` | #### config.json diff --git a/internal/config/config.go b/internal/config/config.go index bade548..2fd7045 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "strconv" ) @@ -73,9 +74,19 @@ func resolveConfigDir() (string, error) { if v := os.Getenv("MF_CONFIG_DIR"); v != "" { return v, nil } - base, err := os.UserConfigDir() + if v := os.Getenv("XDG_CONFIG_HOME"); v != "" && filepath.IsAbs(v) { + return filepath.Join(v, "mf-cli"), nil + } + if runtime.GOOS == "windows" { + base, err := os.UserConfigDir() + if err != nil { + return "", err + } + return filepath.Join(base, "mf-cli"), nil + } + home, err := os.UserHomeDir() if err != nil { return "", err } - return filepath.Join(base, "mf-cli"), nil + return filepath.Join(home, ".config", "mf-cli"), nil } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index deeed95..cd4d366 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "os" "path/filepath" + "runtime" "testing" ) @@ -141,6 +142,63 @@ func TestLoad_InvalidJSON(t *testing.T) { } } +func TestResolveConfigDir_XDGConfigHome(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("Windows does not recognise /custom/xdg as absolute") + } + t.Setenv("MF_CONFIG_DIR", "") + t.Setenv("XDG_CONFIG_HOME", "/custom/xdg") + + dir, err := resolveConfigDir() + if err != nil { + t.Fatalf("resolveConfigDir() returned error: %v", err) + } + want := filepath.Join("/custom/xdg", "mf-cli") + if dir != want { + t.Errorf("resolveConfigDir() = %q, want %q", dir, want) + } +} + +func TestResolveConfigDir_DefaultFallback(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("default fallback on Windows uses AppData, not ~/.config") + } + tmpHome := t.TempDir() + t.Setenv("HOME", tmpHome) + t.Setenv("MF_CONFIG_DIR", "") + t.Setenv("XDG_CONFIG_HOME", "") + + dir, err := resolveConfigDir() + if err != nil { + t.Fatalf("resolveConfigDir() returned error: %v", err) + } + + want := filepath.Join(tmpHome, ".config", "mf-cli") + if dir != want { + t.Errorf("resolveConfigDir() = %q, want %q", dir, want) + } +} + +func TestResolveConfigDir_RelativeXDGIgnored(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("XDG fallback test not applicable on Windows") + } + tmpHome := t.TempDir() + t.Setenv("HOME", tmpHome) + t.Setenv("MF_CONFIG_DIR", "") + t.Setenv("XDG_CONFIG_HOME", "relative/path") + + dir, err := resolveConfigDir() + if err != nil { + t.Fatalf("resolveConfigDir() returned error: %v", err) + } + + want := filepath.Join(tmpHome, ".config", "mf-cli") + if dir != want { + t.Errorf("resolveConfigDir() = %q, want %q (relative XDG_CONFIG_HOME should be ignored)", dir, want) + } +} + func TestRequireClientID_Empty(t *testing.T) { cfg := &Config{ClientID: ""} if err := cfg.RequireClientID(); err == nil { From 906b9b9dd54d73a16824665242017a4ee9b01603 Mon Sep 17 00:00:00 2001 From: beatinaniwa Date: Mon, 30 Mar 2026 02:05:02 +0900 Subject: [PATCH 2/2] =?UTF-8?q?Windows=E3=81=A7=E3=81=AFXDG=5FCONFIG=5FHOM?= =?UTF-8?q?E=E3=82=88=E3=82=8AAppData=E3=82=92=E5=84=AA=E5=85=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git Bash/MSYS環境でXDG_CONFIG_HOMEが設定されていても Windowsでは%AppData%を使用するようXDGチェックの順序を変更 --- internal/config/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 2fd7045..88fab25 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -74,9 +74,6 @@ func resolveConfigDir() (string, error) { if v := os.Getenv("MF_CONFIG_DIR"); v != "" { return v, nil } - if v := os.Getenv("XDG_CONFIG_HOME"); v != "" && filepath.IsAbs(v) { - return filepath.Join(v, "mf-cli"), nil - } if runtime.GOOS == "windows" { base, err := os.UserConfigDir() if err != nil { @@ -84,6 +81,9 @@ func resolveConfigDir() (string, error) { } return filepath.Join(base, "mf-cli"), nil } + if v := os.Getenv("XDG_CONFIG_HOME"); v != "" && filepath.IsAbs(v) { + return filepath.Join(v, "mf-cli"), nil + } home, err := os.UserHomeDir() if err != nil { return "", err