diff --git a/README.md b/README.md index bed58bd..1b6d253 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,14 @@ cd duplicate-file-cleaner pip install -r requirements.txt python main.py ``` + +## Resolução rápida de conflitos no `src/app.py` + +Se após um `git pull` aparecer `IndentationError` com texto como `codex/review-repository-code-...`, usa: + +```bash +python scripts/fix_conflict_artifacts.py src/app.py --write +python -m compileall main.py src +``` + +O script remove marcadores de conflito e artefactos de branch comuns e cria backup automático (`src/app.py.bak`). diff --git a/scripts/fix_conflict_artifacts.py b/scripts/fix_conflict_artifacts.py new file mode 100644 index 0000000..b47addd --- /dev/null +++ b/scripts/fix_conflict_artifacts.py @@ -0,0 +1,68 @@ +from __future__ import annotations + +from pathlib import Path +import argparse +import shutil +import sys + +CONFLICT_PREFIXES = ("<<<<<<<", "=======", ">>>>>>>") + + +def should_remove_line(raw_line: str) -> bool: + stripped = raw_line.strip() + if not stripped: + return False + if stripped.startswith(CONFLICT_PREFIXES): + return True + if stripped.startswith("codex/review-repository-code-"): + return True + if stripped == "main": + return True + return False + + +def sanitize_file(path: Path, write: bool) -> tuple[int, int]: + lines = path.read_text(encoding="utf-8", errors="ignore").splitlines() + cleaned: list[str] = [] + removed = 0 + + for line in lines: + if should_remove_line(line): + removed += 1 + continue + cleaned.append(line) + + if write and removed: + backup = path.with_suffix(path.suffix + ".bak") + shutil.copy2(path, backup) + path.write_text("\n".join(cleaned) + "\n", encoding="utf-8") + + return removed, len(lines) + + +def main() -> int: + parser = argparse.ArgumentParser(description="Remove artefactos de merge em ficheiros Python.") + parser.add_argument("path", nargs="?", default="src/app.py", help="Ficheiro alvo (default: src/app.py)") + parser.add_argument("--write", action="store_true", help="Aplicar alterações ao ficheiro") + args = parser.parse_args() + + target = Path(args.path) + if not target.exists(): + print(f"Ficheiro não encontrado: {target}") + return 1 + + removed, total = sanitize_file(target, write=args.write) + if args.write: + if removed: + print(f"Removidas {removed} linha(s) suspeita(s) de {total}. Backup criado em {target.with_suffix(target.suffix + '.bak')}") + else: + print("Nenhuma linha suspeita encontrada. Nada para alterar.") + else: + print(f"Pré-visualização: {removed} linha(s) suspeita(s) em {total}.") + print("Use --write para aplicar.") + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/app.py b/src/app.py index 9d2b868..8c65c4f 100644 --- a/src/app.py +++ b/src/app.py @@ -33,6 +33,8 @@ def _migrate_legacy_config_if_needed(): if CONFIG_FILE.exists() or not LEGACY_CONFIG_FILE.exists(): return + codex/review-repository-code-hpjdax + codex/review-repository-code-argiid try: legacy_data = json.loads(LEGACY_CONFIG_FILE.read_text(encoding="utf-8")) @@ -46,6 +48,7 @@ def _read_json_file(path: Path): """Le JSON de um ficheiro devolvendo dict vazio em caso de erro.""" try: + main try: legacy_data = json.loads(LEGACY_CONFIG_FILE.read_text(encoding="utf-8")) APP_CONFIG_DIR.mkdir(parents=True, exist_ok=True) @@ -57,7 +60,10 @@ def _read_json_file(path: Path): def _read_json_file(path: Path): """Le JSON de um ficheiro devolvendo dict vazio em caso de erro.""" try: - main + codex/review-repository-code-hpjdax + + +main if path.exists(): with open(path, "r", encoding="utf-8") as f: return json.load(f) @@ -136,6 +142,9 @@ def __init__(self): self.config = load_config() self.scan_paths = [] self._selection_loaded = False + codex/review-repository-code-hpjdax + self.filters_panel_visible = True + codex/review-repository-code-argiid self.filters_panel_visible = True @@ -145,8 +154,8 @@ def __init__(self): codex/review-repository-code-kf47vu self.filters_panel_visible = True + main -> main self.setWindowTitle("Duplicate File Cleaner") self.setMinimumSize(900, 620) @@ -407,6 +416,9 @@ def _build_scan_tab(self): self.scan_mode.currentIndexChanged.connect(self._on_mode_change) mode_layout.addWidget(self.scan_mode) mode_layout.addStretch() +codex/review-repository-code-hpjdax + + codex/review-repository-code-argiid self.toggle_filters_btn = QPushButton("Esconder Selecao") @@ -419,10 +431,17 @@ def _build_scan_tab(self): codex/review-repository-code-l1cd2s + main self.toggle_filters_btn = QPushButton("Esconder Selecao") self.toggle_filters_btn.clicked.connect(self._toggle_filters_panel) mode_layout.addWidget(self.toggle_filters_btn) filter_layout.addLayout(mode_layout) + codex/review-repository-code-hpjdax + + self.filters_panel_widget = self._build_filters_panel() + filter_layout.addWidget(self.filters_panel_widget, 1) + + self.filters_panel_widget = self._build_filters_panel() filter_layout.addWidget(self.filters_panel_widget, 1) @@ -478,6 +497,7 @@ def _build_scan_tab(self): filter_layout.addLayout(custom_layout) main + main main main scan_splitter.addWidget(filter_group)