mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
fix(cloud): emit both - pattern and - pattern/** in rclone filter conversion
Previously `convert_bmignore_to_rclone_filters()` had two bugs: 1. Patterns without wildcards (e.g. `config.json`) were emitted as `- config.json/**`, which only excludes contents of a *directory* named config.json — the actual file passed through unfiltered. 2. Wildcard-only patterns (e.g. `.*`) were emitted as `- .*` alone. rclone globs treat `*` as not crossing `/`, so hidden directory contents (e.g. `.obsidian/workspace.json`) were not excluded. Fix: always emit both `- pattern` (match the item itself) and `- pattern/**` (match directory contents recursively) for every gitignore line, unless it already ends with `/**`. Closes #819 Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com> Signed-off-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
This commit is contained in:
@@ -78,14 +78,25 @@ def convert_bmignore_to_rclone_filters() -> Path:
|
||||
patterns.append(line)
|
||||
continue
|
||||
|
||||
# Convert gitignore pattern to rclone filter syntax
|
||||
# gitignore: node_modules → rclone: - node_modules/**
|
||||
# gitignore: *.pyc → rclone: - *.pyc
|
||||
if "*" in line:
|
||||
# Pattern already has wildcard, just add exclude prefix
|
||||
# Convert gitignore pattern to rclone filter syntax.
|
||||
#
|
||||
# Two rules are always emitted per pattern:
|
||||
# 1. `- pattern` — excludes the item itself (file or dir entry)
|
||||
# 2. `- pattern/**` — excludes all contents when the item is a dir
|
||||
#
|
||||
# Why both? rclone globs treat `*` as not crossing `/`, so:
|
||||
# - `- .*` matches hidden *files* but NOT hidden dir contents
|
||||
# (e.g. `.obsidian/workspace.json` would pass through)
|
||||
# - `- config.json/**` excludes contents of a *dir* named
|
||||
# config.json, but NOT the file config.json itself
|
||||
# Emitting both forms covers files, directories, and directory contents.
|
||||
if line.endswith("/**"):
|
||||
# Trigger: pattern already fully qualified as recursive dir exclude
|
||||
# Why: avoid doubling up on /** suffix
|
||||
# Outcome: written as-is
|
||||
patterns.append(f"- {line}")
|
||||
else:
|
||||
# Directory pattern - add /** for recursive exclude
|
||||
patterns.append(f"- {line}")
|
||||
patterns.append(f"- {line}/**")
|
||||
|
||||
except Exception:
|
||||
|
||||
@@ -32,13 +32,52 @@ def test_convert_bmignore_to_rclone_filters_creates_and_converts(config_home):
|
||||
# Comments/empties preserved
|
||||
assert "# comment" in content
|
||||
assert "" in content
|
||||
# Directory pattern becomes recursive exclude
|
||||
# Each pattern emits both a direct-match and a recursive-contents rule
|
||||
assert "- node_modules" in content
|
||||
assert "- node_modules/**" in content
|
||||
# Wildcard pattern becomes simple exclude
|
||||
assert "- *.pyc" in content
|
||||
assert "- *.pyc/**" in content
|
||||
assert "- .git" in content
|
||||
assert "- .git/**" in content
|
||||
|
||||
|
||||
def test_convert_bmignore_file_pattern_not_mangled_as_directory(config_home):
|
||||
"""Regression: config.json must be excluded as a FILE, not as a dir content glob.
|
||||
|
||||
Previously `config.json` (no wildcard) became `- config.json/**`, which only
|
||||
excludes contents of a *directory* named config.json, leaving the actual file
|
||||
unfiltered during bisync.
|
||||
"""
|
||||
bmignore = get_bmignore_path()
|
||||
bmignore.parent.mkdir(parents=True, exist_ok=True)
|
||||
bmignore.write_text("config.json\n", encoding="utf-8")
|
||||
|
||||
content = convert_bmignore_to_rclone_filters().read_text(encoding="utf-8").splitlines()
|
||||
|
||||
# Must match the file itself
|
||||
assert "- config.json" in content
|
||||
# Also emit the /** form for completeness (covers any hypothetical dir of that name)
|
||||
assert "- config.json/**" in content
|
||||
|
||||
|
||||
def test_convert_bmignore_hidden_glob_covers_directory_contents(config_home):
|
||||
"""Regression: `.*` must exclude hidden directory *contents*, not just hidden files.
|
||||
|
||||
Previously `.*` became `- .*` only. rclone globs don't cross `/`, so
|
||||
`.obsidian/workspace.json` would not be matched by `- .*` alone.
|
||||
"""
|
||||
bmignore = get_bmignore_path()
|
||||
bmignore.parent.mkdir(parents=True, exist_ok=True)
|
||||
bmignore.write_text(".*\n", encoding="utf-8")
|
||||
|
||||
content = convert_bmignore_to_rclone_filters().read_text(encoding="utf-8").splitlines()
|
||||
|
||||
# Must exclude hidden files at any level
|
||||
assert "- .*" in content
|
||||
# Must also exclude contents of hidden directories
|
||||
assert "- .*/**" in content
|
||||
|
||||
|
||||
def test_convert_bmignore_to_rclone_filters_is_cached_when_up_to_date(config_home):
|
||||
bmignore = get_bmignore_path()
|
||||
bmignore.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
Reference in New Issue
Block a user