mirror of
https://github.com/akadeepesh/contextzip.git
synced 2026-10-20 08:36:20 +02:00
feat(cli): enhance exclusion pattern handling and improve user feedback
This commit is contained in:
+17
-11
@@ -927,6 +927,18 @@ def _run(
|
||||
if saved:
|
||||
project_cfg = load_project_config(project_dir)
|
||||
|
||||
# ── Include/exclude inputs shared by every scan mode ─────────────────────
|
||||
# CLI --exclude/-e patterns plus any standing always_exclude patterns from
|
||||
# project config — both are additive, persistent behavior comes from
|
||||
# config.json so it doesn't need to be re-typed every run. always_include
|
||||
# is a standing negation. Built once here so standard and --git-changes
|
||||
# runs honour project config identically.
|
||||
normalized_exclude = [normalize_pattern(p) for p in extra_exclude or []]
|
||||
normalized_exclude += [normalize_pattern(p) for p in project_cfg.always_exclude]
|
||||
force_include = build_force_include_spec(
|
||||
[normalize_pattern(p) for p in project_cfg.always_include]
|
||||
)
|
||||
|
||||
# ── Git-changes mode ─────────────────────────────────────────────────────
|
||||
if git_changes:
|
||||
with console.status("[cyan]Querying git for changed files…[/]", spinner="dots"):
|
||||
@@ -939,7 +951,7 @@ def _run(
|
||||
print_git_deleted_and_submodules(git_result)
|
||||
|
||||
if git_result.is_empty:
|
||||
info("Nothing to package — working tree is clean.")
|
||||
info("Nothing to compress in this one — working tree is clean.")
|
||||
return
|
||||
|
||||
scan_label, scan_detail = git_scan_label_and_detail(git_result)
|
||||
@@ -953,27 +965,21 @@ def _run(
|
||||
large_file_warn_bytes=int(
|
||||
project_cfg.limits.max_file_size_mb * 1024 * 1024
|
||||
),
|
||||
extra_exclude=normalized_exclude if normalized_exclude else None,
|
||||
include_only=include_only if include_only else None,
|
||||
force_include=force_include,
|
||||
)
|
||||
|
||||
else:
|
||||
# ── Build exclusion spec ─────────────────────────────────────────────
|
||||
gitignore_path = None if no_gitignore else (project_dir / ".gitignore")
|
||||
|
||||
# CLI --exclude/-e patterns plus any standing always_exclude patterns
|
||||
# from project config — both are additive, persistent behavior comes
|
||||
# from config.json so it doesn't need to be re-typed every run.
|
||||
normalized_exclude = [normalize_pattern(p) for p in extra_exclude or []]
|
||||
normalized_exclude += [normalize_pattern(p) for p in project_cfg.always_exclude]
|
||||
|
||||
with console.status("[cyan]Building exclusion rules…[/]", spinner="dots"):
|
||||
spec = build_spec(
|
||||
rule_modules=detection.rule_modules,
|
||||
extra_exclude=normalized_exclude if normalized_exclude else None,
|
||||
gitignore_path=gitignore_path,
|
||||
)
|
||||
force_include = build_force_include_spec(
|
||||
[normalize_pattern(p) for p in project_cfg.always_include]
|
||||
)
|
||||
|
||||
# ── Resolve files ─────────────────────────────────────────────────────
|
||||
with console.status("[cyan]Scanning project files…[/]", spinner="dots"):
|
||||
@@ -1027,7 +1033,7 @@ def _run(
|
||||
return
|
||||
|
||||
if not resolved.included:
|
||||
err("Nothing to package — all files were excluded.")
|
||||
err("Nothing to compress in this one — all files were excluded.")
|
||||
info("Try contextzip include PATH or -i PATH to override.")
|
||||
return
|
||||
|
||||
|
||||
+1
-28
@@ -15,38 +15,11 @@ from pathlib import Path
|
||||
from rich.console import Console
|
||||
|
||||
from contextzip.cli_display import print_ai_selection, err, warn, info
|
||||
from contextzip.filters import normalize_pattern # noqa: F401 (re-exported for cli.py)
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pattern normalisation
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def normalize_pattern(p: str) -> str:
|
||||
"""
|
||||
Canonicalise a user-supplied exclusion pattern.
|
||||
|
||||
Rules applied in order:
|
||||
1. Strip a leading ``./`` or ``.\\`` so that ``./CHANGELOG.md``
|
||||
and ``CHANGELOG.md`` are treated identically.
|
||||
2. Replace every backslash with a forward slash for cross-platform
|
||||
consistency (Windows paths entered on the CLI).
|
||||
3. Collapse ``folder/*`` → ``folder/`` so that gitignore-style
|
||||
directory globs work as expected.
|
||||
"""
|
||||
# 1. Strip leading ./ or .\\
|
||||
if p.startswith("./") or p.startswith(".\\"):
|
||||
p = p[2:]
|
||||
# 2. Normalise path separators
|
||||
p = p.replace("\\", "/")
|
||||
# 3. folder/* → folder/
|
||||
if p.endswith("/*"):
|
||||
p = p[:-1]
|
||||
return p
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# AI selection (full run — produces ZIP)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -64,6 +64,10 @@ def print_detection(detection, *, con: Console = console) -> None:
|
||||
"""One line: what was detected and how confident contextzip is."""
|
||||
if detection.is_unknown:
|
||||
ok("Detected", "unknown ecosystem, base rules only", con=con)
|
||||
info(
|
||||
"Don't see your language? Add it here: https://example.com",
|
||||
con=con,
|
||||
)
|
||||
return
|
||||
|
||||
parts = []
|
||||
|
||||
Reference in New Issue
Block a user