fix(cli): ignore generated folders by default

- Skip .comments, virtualenvs, env files, VCS folders, and OS metadata in sync.
- Apply defaults before project .nanoshareignore and repeatable --ignore rules.
- Cover default ignores for local uploads and direct pattern matching.
This commit is contained in:
2026-07-27 22:01:52 +02:00
parent 472ed11e9f
commit ffdcc979e6
2 changed files with 40 additions and 2 deletions
+21 -1
View File
@@ -4,9 +4,29 @@ from fnmatch import fnmatch
from pathlib import Path from pathlib import Path
IGNORE_FILE_NAME = '.nanoshareignore' IGNORE_FILE_NAME = '.nanoshareignore'
DEFAULT_IGNORE_PATTERNS = [
IGNORE_FILE_NAME,
'.comments/',
'.env',
'.env.*',
'.venv/',
'venv/',
'__pycache__/',
'.pytest_cache/',
'.mypy_cache/',
'.ruff_cache/',
'.git/',
'.hg/',
'.svn/',
'.DS_Store',
'Thumbs.db',
'desktop.ini',
'$RECYCLE.BIN/',
'System Volume Information/',
]
def load_ignore_patterns(root: Path, extra_patterns: list[str] | None = None) -> list[str]: def load_ignore_patterns(root: Path, extra_patterns: list[str] | None = None) -> list[str]:
patterns = [IGNORE_FILE_NAME] patterns = list(DEFAULT_IGNORE_PATTERNS)
ignore_file = root / IGNORE_FILE_NAME ignore_file = root / IGNORE_FILE_NAME
if ignore_file.is_file(): if ignore_file.is_file():
for line in ignore_file.read_text().splitlines(): for line in ignore_file.read_text().splitlines():
+19 -1
View File
@@ -9,7 +9,7 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'cli'))
from nanoshare_client import cli from nanoshare_client import cli
from nanoshare_client.auth import _CallbackServer from nanoshare_client.auth import _CallbackServer
from nanoshare_client.completion import script as completion_script from nanoshare_client.completion import script as completion_script
from nanoshare_client.ignore import is_ignored from nanoshare_client.ignore import load_ignore_patterns, is_ignored
from nanoshare_client.table import format_table from nanoshare_client.table import format_table
class FakeClient: class FakeClient:
@@ -210,6 +210,12 @@ def test_sync_ignores_local_files_from_nanoshareignore(tmp_path, monkeypatch):
(tmp_path / 'cache').mkdir() (tmp_path / 'cache').mkdir()
(tmp_path / 'cache' / 'ignored.txt').write_text('ignored') (tmp_path / 'cache' / 'ignored.txt').write_text('ignored')
(tmp_path / 'scratch.tmp').write_text('ignored') (tmp_path / 'scratch.tmp').write_text('ignored')
(tmp_path / '.comments').mkdir()
(tmp_path / '.comments' / 'ignored.xml').write_text('<comment />')
(tmp_path / '.env').write_text('SECRET=ignored')
(tmp_path / '.venv').mkdir()
(tmp_path / '.venv' / 'ignored.py').write_text('ignored')
(tmp_path / 'Thumbs.db').write_text('ignored')
code = cli.main([ code = cli.main([
'sync', 'sync',
@@ -250,6 +256,18 @@ def test_ignore_patterns_match_files_and_directories():
assert is_ignored('docs/page.draft.md', patterns) assert is_ignored('docs/page.draft.md', patterns)
assert not is_ignored('docs/page.md', patterns) assert not is_ignored('docs/page.md', patterns)
def test_default_ignore_patterns_skip_common_generated_files(tmp_path):
patterns = load_ignore_patterns(tmp_path)
assert is_ignored('.comments/comment.xml', patterns)
assert is_ignored('.env', patterns)
assert is_ignored('.env.local', patterns)
assert is_ignored('.venv/bin/python', patterns)
assert is_ignored('venv/bin/python', patterns)
assert is_ignored('__pycache__/mod.pyc', patterns)
assert is_ignored('nested/Thumbs.db', patterns)
assert not is_ignored('docs/note.txt', patterns)
def test_completion_scripts_include_commands(): def test_completion_scripts_include_commands():
zsh = completion_script('zsh') zsh = completion_script('zsh')
bash = completion_script('bash') bash = completion_script('bash')