From 541ef488bbb4a6adc4739ea5d7ad74e5da78725e Mon Sep 17 00:00:00 2001 From: Michal Tuszowski Date: Wed, 17 Sep 2025 23:48:15 +0200 Subject: [PATCH] aa --- import.py | 71 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/import.py b/import.py index 453a169..4cb8324 100644 --- a/import.py +++ b/import.py @@ -71,18 +71,37 @@ def copy_contents(src_dir: str, dst_dir: str): def git_has_staged_changes(repo: str) -> bool: # Po "git add -A" sprawdzamy, czy coś jest w indexie res = subprocess.run(["git", "diff", "--cached", "--quiet"], cwd=repo) - return res.returncode == 1 # 1 = są zmiany; 0 = brak; inne = błąd (ignorujemy tutaj) + return res.returncode == 1 # 1 = są zmiany; 0 = brak def git_is_clean(repo: str) -> bool: res = run(["git", "status", "--porcelain"], cwd=repo, capture=True, check=False) return res.stdout.strip() == "" +def ensure_subdir(repo_root: str, subdir: str) -> str: + """Zwraca absolutną ścieżkę docelowego podkatalogu w repo, tworząc go jeśli trzeba. + Zabezpiecza przed wychodzeniem poza repo (..).""" + target = repo_root + if subdir: + target = os.path.abspath(os.path.join(repo_root, subdir)) + repo_root_abs = os.path.abspath(repo_root) + # Bezpieczeństwo: podkatalog musi być wewnątrz repo + if os.path.commonpath([target, repo_root_abs]) != repo_root_abs: + eprint(f"[BŁĄD] Niedozwolona ścieżka podkatalogu: {subdir}") + sys.exit(1) + os.makedirs(target, exist_ok=True) + return target + def main(): parser = argparse.ArgumentParser( description="Import archiwów ZIP do repozytorium git (od najstarszego), z commitami po każdym ZIPie." ) parser.add_argument("--zip-dir", required=True, help="Katalog z plikami .zip") parser.add_argument("--repo", required=True, help="Katalog repozytorium git (cel)") + parser.add_argument( + "--subdir", + default="", + help="Opcjonalny podkatalog w repo, do którego mają trafić pliki (utworzony jeśli nie istnieje).", + ) parser.add_argument( "--allow-dirty", action="store_true", @@ -97,6 +116,7 @@ def main(): args = parser.parse_args() zip_dir = os.path.abspath(args.zip_dir) repo = os.path.abspath(args.repo) + subdir = args.subdir.strip() if not os.path.isdir(zip_dir): eprint(f"[BŁĄD] Nie ma katalogu: {zip_dir}") @@ -108,6 +128,8 @@ def main(): eprint(f"[BŁĄD] {repo} nie wygląda na repozytorium git (brak .git).") sys.exit(1) + target_dir = ensure_subdir(repo, subdir) # gdzie właściwie kopiujemy zawartość ZIPów + if not args.allow_dirty and not git_is_clean(repo): eprint("[BŁĄD] Repo nie jest czyste. Użyj --allow-dirty, jeśli chcesz mimo to kontynuować.") sys.exit(1) @@ -117,7 +139,10 @@ def main(): print("[INFO] Brak plików .zip do przetworzenia.") return + rel_target = os.path.relpath(target_dir, repo) + print(f"[INFO] Cel importu: {target_dir} (rel: {rel_target})") print(f"[INFO] Znaleziono {len(zips)} archiwów .zip do przetworzenia (od najstarszego do najnowszego).") + for i, zip_path in enumerate(zips, start=1): zip_name = os.path.basename(zip_path) mtime = datetime.fromtimestamp(os.path.getmtime(zip_path), tz=timezone.utc) @@ -126,10 +151,10 @@ def main(): print(f"\n=== [{i}/{len(zips)}] {zip_name} (mtime: {mtime_iso}) ===") if args.dry_run: - print(f"[DRY-RUN] Rozpakowałbym {zip_name} i zrobił commit.") + print(f"[DRY-RUN] Rozpakowałbym {zip_name} do '{rel_target}' i zrobił commit.") continue - # Rozpakuj najpierw do katalogu tymczasowego + # Rozpakuj do katalogu tymczasowego (stage) stage_dir = tempfile.mkdtemp(prefix="zipstage_") try: with zipfile.ZipFile(zip_path, "r") as zf: @@ -139,32 +164,30 @@ def main(): shutil.rmtree(stage_dir, ignore_errors=True) continue - # BONUS: wykrywanie rekursywne struktury katalogów z module.json + # BONUS: wykrywanie rekursywne module.json stage_root_mjson = os.path.join(stage_dir, "module.json") + effective_root = None if os.path.isfile(stage_root_mjson): - # idealnie: module.json już w korzeniu paczki effective_root = stage_dir print("[OK] Wykryto module.json w korzeniu archiwum.") else: matches = find_module_json(stage_dir) if len(matches) == 1: - # jednoznaczny kandydat -> uznaj katalog z module.json za korzeń i skopiuj stamtąd effective_root = os.path.dirname(matches[0]) rel = os.path.relpath(effective_root, stage_dir) print(f"[BONUS] Wykryto zagnieżdżenie: module.json w '{rel}'. " - f"Kopiuję zawartość tego katalogu do repozytorium.") + f"Kopiuję zawartość tego katalogu do '{rel_target}'.") else: - # 0 lub >1 -> pauza i instrukcja ręczna - print("[UWAGA] Nie wykryto jednoznacznie położenia module.json " - "(0 lub wiele wystąpień).") + print("[UWAGA] Nie wykryto jednoznacznie położenia module.json (0 lub wiele wystąpień).") if matches: print("Kandydaci:") for p in matches: print(f" - {os.path.relpath(p, stage_dir)}") print("\nProszę **ręcznie** przenieść/rozpakować pliki z poniższego katalogu tymczasowego") - print(f"do właściwego miejsca w repo: {repo}") + print(f"do właściwego miejsca w repo: {target_dir}") print(f"Katalog tymczasowy: {stage_dir}") - print("Cel: po ułożeniu plików, w repo ma być poprawny układ projektu (typowo: module.json w korzeniu).") + print("Cel: po ułożeniu plików, w docelowym podkatalogu powinna być poprawna struktura (typowo: module.json w korzeniu).") + choice = "" while True: try: choice = input("Po wykonaniu zmian naciśnij [Enter], aby kontynuować, " @@ -176,29 +199,24 @@ def main(): if choice == "q": print("Kończę działanie na życzenie użytkownika.") sys.exit(0) - if choice == "s": - print("Pomijam to archiwum.") - shutil.rmtree(stage_dir, ignore_errors=True) - effective_root = None + if choice in ("", "s"): break - # Enter -> spróbujmy zrobić commit tego, co jest w repo - effective_root = None # nic nie kopiujemy automatycznie - break - # jeśli pominięto - if effective_root is None and choice == "s": + if choice == "s": + print("Pomijam to archiwum.") + shutil.rmtree(stage_dir, ignore_errors=True) continue + # Enter -> nic nie kopiujemy automatycznie, zakładamy że użytkownik przeniósł co trzeba - # Jeśli mamy effective_root (auto), kopiujemy zawartość do repo + # Jeśli mamy effective_root (auto), kopiujemy zawartość do docelowego podkatalogu if effective_root: - copy_contents(effective_root, repo) + copy_contents(effective_root, target_dir) - # Git add + commit (jeśli są zmiany) + # Git add + commit (jeśli są zmiany) – commit z korzenia repo run(["git", "add", "-A"], cwd=repo) if git_has_staged_changes(repo): - msg = f"Import {zip_name} ({mtime_iso})" + msg = f"Import {zip_name} do {rel_target} ({mtime_iso})" env = os.environ.copy() - # Ustaw datę commita na mtime pliku ZIP (ładny, historyczny timeline) env["GIT_AUTHOR_DATE"] = mtime_iso env["GIT_COMMITTER_DATE"] = mtime_iso run(["git", "commit", "-m", msg], cwd=repo, env=env) @@ -210,6 +228,7 @@ def main(): shutil.rmtree(stage_dir, ignore_errors=True) print("\n[ZAKOŃCZONE] Przetwarzanie archiwów .zip zakończone.") + print(f"[INFO] Pliki zostały umieszczone w: {target_dir}") if __name__ == "__main__": main()