fix(jlcpcb): use platform user data dir for parts database (#167)

JLCPCBPartsManager defaulted db_path to a "data/" directory computed
relative to __file__, which fails with read-only filesystems when the
package is installed to a system-managed prefix (e.g. /nix/store, an
immutable container image, or /usr/lib). The same pattern in
download_jlcpcb.py would silently scatter the ~1.5 GB JLCPCB cache
inside the install tree even when it is writable.

The original integration plan (docs/archive/JLCPCB_INTEGRATION_PLAN.md)
called for a per-user database under ~/.kicad-mcp/. This change moves
the default to the platform-appropriate user data directory by adding
a new PlatformHelper.get_data_dir() helper that mirrors the existing
get_config_dir() / get_cache_dir() conventions:

  - Linux:   XDG_DATA_HOME/kicad-mcp or ~/.local/share/kicad-mcp
  - macOS:   ~/Library/Application Support/kicad-mcp
  - Windows: %USERPROFILE%\.kicad-mcp\data

Both JLCPCBPartsManager and download_jlcpcb.py now resolve their
database paths through this helper. ensure_directories() and
detect_platform() include the new directory. Unit tests parallel to
the existing config_dir/cache_dir cases cover platform-appropriate
paths and the relative-XDG_DATA_HOME edge case.
This commit is contained in:
Sean Link
2026-05-18 11:40:13 -07:00
committed by GitHub
parent 5c6b55453e
commit 4e845f24ce
4 changed files with 86 additions and 8 deletions

View File

@@ -69,6 +69,45 @@ class TestPathGeneration:
assert cache_dir.exists(), f"Cache dir should exist: {cache_dir}"
assert cache_dir.is_dir(), f"Cache dir should be a directory: {cache_dir}"
def test_data_dir_exists_after_ensure(self):
"""Test that data directory is created"""
PlatformHelper.ensure_directories()
data_dir = PlatformHelper.get_data_dir()
assert data_dir.exists(), f"Data dir should exist: {data_dir}"
assert data_dir.is_dir(), f"Data dir should be a directory: {data_dir}"
def test_data_dir_is_platform_appropriate(self):
"""Test that data directory follows platform conventions"""
data_dir = PlatformHelper.get_data_dir()
if PlatformHelper.is_linux():
# Should be ~/.local/share/kicad-mcp or $XDG_DATA_HOME/kicad-mcp
xdg = os.environ.get("XDG_DATA_HOME")
if xdg and Path(xdg).is_absolute():
expected = Path(xdg) / "kicad-mcp"
else:
expected = Path.home() / ".local" / "share" / "kicad-mcp"
assert data_dir == expected
elif PlatformHelper.is_windows():
# Should be %USERPROFILE%\.kicad-mcp\data
expected = Path.home() / ".kicad-mcp" / "data"
assert data_dir == expected
elif PlatformHelper.is_macos():
# Should be ~/Library/Application Support/kicad-mcp
expected = Path.home() / "Library" / "Application Support" / "kicad-mcp"
assert data_dir == expected
def test_data_dir_ignores_relative_xdg_data_home(self, monkeypatch):
"""Relative XDG_DATA_HOME should be ignored on Linux."""
monkeypatch.setattr(PlatformHelper, "is_linux", staticmethod(lambda: True))
monkeypatch.setattr(PlatformHelper, "is_windows", staticmethod(lambda: False))
monkeypatch.setattr(PlatformHelper, "is_macos", staticmethod(lambda: False))
monkeypatch.setenv("XDG_DATA_HOME", "relative/data")
assert PlatformHelper.get_data_dir() == Path.home() / ".local" / "share" / "kicad-mcp"
def test_config_dir_is_platform_appropriate(self):
"""Test that config directory follows platform conventions"""
config_dir = PlatformHelper.get_config_dir()
@@ -146,6 +185,7 @@ class TestDetectPlatform:
"config_dir",
"log_dir",
"cache_dir",
"data_dir",
"kicad_python_paths",
]
for key in required_keys: