mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-20 04:21:23 +00:00
119 lines
3.9 KiB
Python
Generated
119 lines
3.9 KiB
Python
Generated
#!/usr/bin/env python3
|
|
"""Publish module - Copy versioned artifacts to download/ paths for fresh installs"""
|
|
|
|
from typing import Dict, List, Tuple
|
|
|
|
from ...common.context import Context
|
|
from ...common.module import CommandModule, ValidationError
|
|
from ...common.utils import log_info, log_error, log_success, log_warning
|
|
from ..storage import BOTO3_AVAILABLE, get_r2_client
|
|
from .common import (
|
|
PLATFORMS,
|
|
PLATFORM_DISPLAY_NAMES,
|
|
DOWNLOAD_PATH_MAPPING,
|
|
fetch_all_release_metadata,
|
|
)
|
|
|
|
|
|
def copy_to_download_path(
|
|
client,
|
|
bucket: str,
|
|
source_key: str,
|
|
dest_key: str,
|
|
) -> bool:
|
|
"""Copy object within R2 bucket"""
|
|
try:
|
|
client.copy_object(
|
|
Bucket=bucket,
|
|
CopySource={"Bucket": bucket, "Key": source_key},
|
|
Key=dest_key,
|
|
)
|
|
return True
|
|
except Exception as e:
|
|
log_error(f"Failed to copy {source_key} → {dest_key}: {e}")
|
|
return False
|
|
|
|
|
|
class PublishModule(CommandModule):
|
|
"""Copy versioned artifacts to download/ paths (make release "live")"""
|
|
|
|
produces = []
|
|
requires = []
|
|
description = "Publish versioned artifacts to latest download URLs"
|
|
|
|
def __init__(self, platforms: List[str] = None):
|
|
self.platforms = platforms or PLATFORMS
|
|
|
|
def validate(self, ctx: Context) -> None:
|
|
if not BOTO3_AVAILABLE:
|
|
raise ValidationError(
|
|
"boto3 library not installed - run: pip install boto3"
|
|
)
|
|
|
|
if not ctx.env.has_r2_config():
|
|
raise ValidationError("R2 configuration not set")
|
|
|
|
if not ctx.release_version:
|
|
raise ValidationError("--version is required")
|
|
|
|
def execute(self, ctx: Context) -> None:
|
|
version = ctx.release_version
|
|
env = ctx.env
|
|
|
|
metadata = fetch_all_release_metadata(version, env)
|
|
if not metadata:
|
|
log_error(f"No release metadata found for version {version}")
|
|
return
|
|
|
|
log_info(f"\n{'='*60}")
|
|
log_info(f"Publishing v{version} to download/ paths")
|
|
log_info(f"{'='*60}")
|
|
|
|
client = get_r2_client(env)
|
|
if not client:
|
|
log_error("Failed to create R2 client")
|
|
return
|
|
|
|
results: List[Tuple[str, str, bool]] = []
|
|
|
|
for platform in self.platforms:
|
|
if platform not in metadata:
|
|
log_warning(f"Skipping {platform}: no release metadata")
|
|
continue
|
|
|
|
release = metadata[platform]
|
|
artifacts = release.get("artifacts", {})
|
|
platform_mapping = DOWNLOAD_PATH_MAPPING.get(platform, {})
|
|
|
|
log_info(f"\n{PLATFORM_DISPLAY_NAMES[platform]}:")
|
|
|
|
for artifact_key, artifact in artifacts.items():
|
|
if artifact_key not in platform_mapping:
|
|
log_info(f" Skipping {artifact_key}: no download path mapping")
|
|
continue
|
|
|
|
dest_path = platform_mapping[artifact_key]
|
|
# Extract source key from URL (after CDN base)
|
|
url = artifact["url"]
|
|
source_key = f"releases/{version}/{platform}/{artifact['filename']}"
|
|
|
|
log_info(f" Copying {artifact['filename']} → {dest_path}")
|
|
success = copy_to_download_path(client, env.r2_bucket, source_key, dest_path)
|
|
results.append((artifact["filename"], dest_path, success))
|
|
|
|
if success:
|
|
log_success(f" ✓ Published to {env.r2_cdn_base_url}/{dest_path}")
|
|
|
|
# Summary
|
|
log_info(f"\n{'='*60}")
|
|
succeeded = sum(1 for _, _, ok in results if ok)
|
|
failed = sum(1 for _, _, ok in results if not ok)
|
|
|
|
if failed == 0:
|
|
log_success(f"Published {succeeded} artifact(s) to download/ paths")
|
|
else:
|
|
log_warning(f"Published {succeeded}/{succeeded + failed} artifact(s)")
|
|
for filename, dest, ok in results:
|
|
if not ok:
|
|
log_error(f" Failed: {filename} → {dest}")
|