Faithful port of GOLD's GoogleDriveSync against the live @api gateway. Completes the backup restoration (master FPLAN-0264). Drive pipeline (handlers/drive/): - DriveClient: folder hierarchy 'AIPass Backups/<project>/', thread-safe cache, retry-with-rebuild. Auth via aipass.api get_drive_service + api_call_with_retry (never console-OAuth). - upload.py: resumable MediaFileUpload, 3 threaded workers, single + batch. - tracker.py: mtime+size dedup (.backup_system/drive_tracker.json) — no re-upload of unchanged files. - test.py: connectivity check. All 4 drive_* modules un-stubbed. all = snapshot->versioned->drive-sync, drive step FAILS HONESTLY if creds absent (no silent skip, snapshot+versioned still run). restore command (modules/restore.py -> handlers/diff/restore.py): - 'restore <project> list <file>' (baseline + current + diffs) - 'restore <project> file <file> <out>' (reconstruct + write) pyright/cleanup (Patrick's call): removed backup's standalone pyrightconfig.json (pre-namespace leftover, archived) so it inherits the repo-root config like every citizen; dead PyQt5 ui/settings_window.py archived. Drive tests fully mocked — ZERO real Google calls in CI. Live Drive upload awaits Google OAuth creds (~/.secrets/aipass/google_client_secret.json + drone @api reauth google) — Patrick's setup step. Verified by artifact (devpulse): seedgo 100% all 36 standards / 37 files, 187 tests, ruff clean; restore list/file round-trip confirmed live. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
96 lines
2.6 KiB
Python
96 lines
2.6 KiB
Python
# =================== AIPass ====================
|
|
# Name: drive_test.py
|
|
# Description: Drive test module — verifies Google Drive connectivity via @api
|
|
# Version: 1.0.0
|
|
# Created: 2026-04-17
|
|
# Modified: 2026-06-12
|
|
# =============================================
|
|
|
|
"""Drive Test Module — tests Drive auth through @api gateway."""
|
|
|
|
import sys
|
|
|
|
from aipass.prax import logger
|
|
from aipass.cli.apps.modules import console
|
|
|
|
from aipass.backup.apps.handlers.json import json_handler
|
|
|
|
|
|
MODULE_NAME = "drive_test"
|
|
PRIMARY_COMMAND = "drive-test"
|
|
|
|
|
|
def print_introspection():
|
|
"""Display module info and connected handlers."""
|
|
console.print(f"[bold cyan]{MODULE_NAME} Module[/bold cyan]")
|
|
console.print(f" Primary command: [yellow]{PRIMARY_COMMAND}[/yellow]")
|
|
console.print(" Status: Phase 4 -- auth test via @api gateway")
|
|
console.print(" Handlers: drive/client, drive/test")
|
|
|
|
|
|
def print_help():
|
|
"""Display help for this module."""
|
|
print_introspection()
|
|
|
|
|
|
def run_drive_test() -> bool:
|
|
"""Test Drive auth through @api gateway.
|
|
|
|
Creates a DriveClient, authenticates, tests folder access, and
|
|
displays results.
|
|
|
|
Returns:
|
|
True if connectivity test passed, False otherwise.
|
|
"""
|
|
from aipass.backup.apps.handlers.drive.client import DriveClient
|
|
from aipass.backup.apps.handlers.drive.test import test_connectivity
|
|
|
|
client = DriveClient()
|
|
result = test_connectivity(client)
|
|
|
|
if result["success"]:
|
|
console.print("[green]Drive connectivity test PASSED[/green]")
|
|
console.print(f" Backup folder ID: {result['folder_id']}")
|
|
logger.info("[backup] Drive test passed")
|
|
else:
|
|
console.print(f"[red]Drive connectivity test FAILED: {result['error']}[/red]")
|
|
logger.warning(f"[backup] Drive test failed: {result['error']}")
|
|
|
|
json_handler.log_operation(
|
|
"drive_test_complete",
|
|
{"success": result["success"]},
|
|
)
|
|
return result["success"]
|
|
|
|
|
|
def handle_command(command: str, args: list) -> bool:
|
|
"""Handle the drive-test command. Returns True if handled."""
|
|
if command != PRIMARY_COMMAND:
|
|
return False
|
|
|
|
if not args:
|
|
print_introspection()
|
|
return True
|
|
|
|
if args[0] in ("--help", "-h", "help"):
|
|
print_help()
|
|
return True
|
|
|
|
if args[0] == "run":
|
|
run_drive_test()
|
|
return True
|
|
|
|
# Default: run the test
|
|
run_drive_test()
|
|
return True
|
|
|
|
|
|
# =============================================
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) == 1:
|
|
print_introspection()
|
|
sys.exit(0)
|
|
result = handle_command(PRIMARY_COMMAND, sys.argv[1:])
|
|
sys.exit(0 if result else 1)
|