(tier_key=None)
| 1646 | handle.write("=" * 56 + "\n") |
| 1647 | handle.write("\n".join(report_lines).rstrip() + "\n") |
| 1648 | |
| 1649 | def _build_project_save_archive(archive_path): |
| 1650 | """Create a recoverable multi-project backup and continue after item failures.""" |
| 1651 | _remove_path_if_exists(PROJECT_SAVE_WORKDIR) |
| 1652 | os.makedirs(PROJECT_SAVE_WORKDIR, exist_ok=True) |
| 1653 | |
| 1654 | bundle_root = os.path.join(PROJECT_SAVE_WORKDIR, PROJECT_SAVE_BUNDLE_DIRNAME) |
| 1655 | apks_dir = os.path.join(bundle_root, "APKs") |
| 1656 | repos_dir = os.path.join(bundle_root, "Repositories") |
| 1657 | os.makedirs(apks_dir, exist_ok=True) |
| 1658 | os.makedirs(repos_dir, exist_ok=True) |
| 1659 | report_lines = [pipboy_text("Created: ", "Δημιουργήθηκε: ") + time.strftime('%Y-%m-%d %H:%M:%S'), ""] |
| 1660 | failures = 0 |
| 1661 | |
| 1662 | report_lines.append(pipboy_text("APKs:", "APK αρχεία:")) |
| 1663 | for apk_source in PROJECT_SAVE_APK_SOURCES: |
| 1664 | target_path = os.path.join(apks_dir, apk_source["filename"]) |
| 1665 | try: |
| 1666 | if apk_source["type"] == "direct": |
| 1667 | apk_url = apk_source["url"] |
| 1668 | else: |
| 1669 | apk_url = _resolve_fdroid_package_apk_url(apk_source["package"]) |
| 1670 | _download_file_silent(apk_url, target_path) |
| 1671 | report_lines.append(pipboy_text("- INCLUDED: ", "- ΣΥΜΠΕΡΙΛΗΦΘΗΚΕ: ") + apk_source['filename']) |
| 1672 | except Exception as exc: |
| 1673 | failures += 1 |
| 1674 | report_lines.append(pipboy_text("- FAILED: ", "- ΑΠΟΤΥΧΙΑ: ") + f"{apk_source['filename']} — {exc}") |
| 1675 | pipboy_log_error(f"backup APK {apk_source['filename']}", exc) |
| 1676 | |
| 1677 | report_lines.extend(["", pipboy_text("Repositories (smallest to largest):", "Αποθετήρια (από το μικρότερο στο μεγαλύτερο):")]) |
| 1678 | ordered_repositories, repository_size_map = _ordered_project_save_repositories() |
| 1679 | for repo_source in ordered_repositories: |
| 1680 | repo_target_dir = os.path.join(repos_dir, repo_source["folder_name"]) |
| 1681 | owner, repository = _project_save_github_identity(repo_source.get("url")) |
| 1682 | size_kb = repository_size_map.get((owner.casefold(), repository.casefold())) if owner and repository else None |
| 1683 | size_note = f" [{size_kb / 1024:.2f} MB]" if size_kb is not None else " [size unavailable]" |
| 1684 | local_source = _project_save_local_source(repo_source) |
| 1685 | try: |
| 1686 | if local_source: |
| 1687 | _copy_local_project_for_backup(local_source, repo_target_dir) |
| 1688 | report_lines.append( |
| 1689 | pipboy_text("- INCLUDED LOCAL STATE: ", "- ΣΥΜΠΕΡΙΛΗΦΘΗΚΕ ΤΟΠΙΚΗ ΚΑΤΑΣΤΑΣΗ: ") + f"{repo_source['project_name']}{size_note} — {local_source}" |
| 1690 | ) |
| 1691 | else: |
| 1692 | _clone_repository_silent(repo_source["url"], repo_target_dir) |
| 1693 | report_lines.append( |
| 1694 | pipboy_text("- INCLUDED REMOTE SNAPSHOT: ", "- ΣΥΜΠΕΡΙΛΗΦΘΗΚΕ ΑΠΟΜΑΚΡΥΣΜΕΝΟ ΣΤΙΓΜΙΟΤΥΠΟ: ") + f"{repo_source['project_name']}{size_note} — {repo_source['url']}" |
| 1695 | ) |
| 1696 | except Exception as exc: |
| 1697 | failures += 1 |
| 1698 | _remove_path_if_exists(repo_target_dir) |
| 1699 | report_lines.append(pipboy_text("- FAILED: ", "- ΑΠΟΤΥΧΙΑ: ") + f"{repo_source['project_name']} — {exc}") |
| 1700 | pipboy_log_error(f"backup repository {repo_source['project_name']}", exc) |
no test coverage detected