Initial: Roko Backup Script v2 — Python rewrite with streaming progress & log rotation

Current deployed version (roko-backup.py) after refactoring from bash to Python.
Generated via OpenCode (kimi-k2.7-code). Includes:
- rclone streaming progress (log every 5% or 30s)
- RotatingFileHandler (max 1MB, 5 backups)
- LockFile for concurrent run prevention
- Yandex Cloud upload with NO_PROXY bypass
- Also includes comparison versions from mimo-v2.5-pro and kimi-k2.7-code
This commit is contained in:
Roko
2026-07-07 11:27:02 +07:00
commit a88b2604a1
5 changed files with 2362 additions and 0 deletions
+94
View File
@@ -0,0 +1,94 @@
# Refactoring №2: roko-backup.py — улучшенная версия
## Исходный код
`/home/openclaw/.openclaw/scripts/roko-backup.py` (текущая версия — 8 классов, 380 строк)
## ✅ Сохранить
- Архитектуру (конвейер: Config → LockFile → Collector → Archiver → Uploader → Verifier → Cleaner → Reporter → BackupPipeline)
- Python 3.10+, только stdlib + rclone subprocess
- argparse (--config, --dry-run, --verbose)
- LockFile (защита от параллельных запусков)
- NO_PROXY для Yandex Cloud в subprocess env
- Exponential backoff (10s, 30s, 60s) на retry
## 🆕 Новый функционал
### 1. Streaming rclone progress
- Сейчас: `subprocess.run(capture_output=True)` — ждём завершения, потом показываем вывод
- Надо: `subprocess.Popen` с построчным чтением stderr в реальном времени
- rclone с `--progress` пишет progress строки в stderr
- **Формат вывода в логах:**
```
2026-07-07 10:30:15 INFO Upload: 15% (95 MiB / 622 MiB) @ 2.1 MiB/s
```
- Парсить `Transferred: ... MiB / ... MiB, ...%` из rclone stderr
- Не flood-ить лог — логировать прогресс раз в 30 секунд или при каждом новом проценте (кратном 5%)
- По завершении показать финальную статистику (скорость, время)
### 2. Ротация логов
- Лог-файл: `/home/openclaw/backups/roko-backup.log` (НА ДИСКЕ, не в /tmp!)
- Максимальный размер: 1 МБ (после этого ротация)
- Хранить: 5 последних ротированных логов (`roko-backup.log.1`, `.2`, ... `.5`)
- Использовать `logging.handlers.RotatingFileHandler` из stdlib
- При `--verbose` — дублировать в stdout тоже (для отладки вручную)
### 3. Улучшения кода
- **Type hints** полные, включая `collections.abc.Generator`, `ContextManager`
- **Меньше повторений** — RCLONE_ENV дублируется в Uploader/Verifier/Cleaner, вынести в конфиг или хелпер
- **Документация** — docstrings по PEP 257 на английском (краткие, по делу)
- **Error handling** — отдельный класс BackupError(Exception) вместо голых return 3
- **Cleanup гарантированный** — даже при падении архиватор должен подчищать staging
## Структура (сохраняем конвейер, улучшаем детали)
```python
class BackupError(Exception): ...
class LockError(BackupError): ...
@dataclass(frozen=True)
class Config:
# добавляем log_file: Path, max_log_size: int, max_log_backups: int
...
class LockFile(ContextManager): # добавить __enter__/__exit__
...
class Collector:
EXCLUDE_PATTERNS = (...) # можно сделать конфигурируемым в Config
...
class Archiver:
# архивирует через tarfile (не subprocess tar)
...
class Uploader:
# subprocess.Popen + streaming stderr для progress
UPLOAD_PROGRESS_INTERVAL = 30 # секунд между логами прогресса
PROGRESS_PERCENT_STEP = 5 # логировать каждые N процентов
...
class Verifier: ...
class Cleaner: ...
class Reporter: ...
class BackupPipeline: ...
def setup_logging(verbose, log_file, max_size, max_backups): ...
def main(): ...
```
## Требования к качеству
- `python3 -c "import ast; ast.parse(open('roko-backup.py').read())"` — OK
- `--dry-run --verbose` — работает, показывает все источники
- Без аргументов — полный цикл без ошибок
- `--config X` — работает
- `python3 -c "from roko_backup import Config, BackupPipeline"` — импортируемый модуль
## Файлы
- Пишем: `/home/openclaw/.openclaw/scripts/roko-backup.py` (перезаписать)
- Сохраняем: `roko-backup.py.bak` (текущая версия)
- README: обновить `/home/openclaw/.openclaw/scripts/README.md` (добавить про логи и streaming)
## Модели для OpenCode
- **Основная:** mimo-v2.5-pro (OpenCode Go)
- **Сравнение:** kimi-k2.7-code (OpenCode Go)
- **Запасные при зависании (до 3 попыток):** minimax-m3 (OpenCode Go), deepseek-v4-pro (OpenCode Go)