Build optimization: pre-built PM3 binaries, ARM64 CI, base image caching
Replace PM3 compile-from-source in pi-gen with pre-built tarball extraction (saves 43-58 min). Merge stagePM3 into stageDangerousPi as 02-pm3-install substage, renumber all subsequent substages. Switch CI PM3 build to native ARM64 runner (ubuntu-24.04-arm64) eliminating QEMU overhead. Add weekly base-image workflow for pre-baking stages 0-2. Support PM3_TARBALL, BASE_IMAGE, and APT_PROXY env vars in build-image.sh. Also includes prior Phase 5 work: theme system, design system integration, component update system, OS updates, CI build pipeline, and test results. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,9 +3,12 @@
|
||||
This service provides software update operations that can be consumed by
|
||||
multiple interfaces (REST API, BLE GATT, etc.).
|
||||
"""
|
||||
from typing import Optional, Dict, Any
|
||||
from dataclasses import asdict
|
||||
from typing import Optional, Dict, Any, List
|
||||
|
||||
from ..managers.update_manager import UpdateManager, UpdateProgress, UpdateStatus
|
||||
from ..managers.update_manager import (
|
||||
UpdateManager, UpdateProgress, UpdateStatus, ComponentId,
|
||||
)
|
||||
from .pm3_service import PM3ServiceError, PM3ServiceResult
|
||||
|
||||
|
||||
@@ -156,6 +159,15 @@ class UpdateService:
|
||||
try:
|
||||
progress = await self.update_manager.get_progress()
|
||||
|
||||
comp_list = []
|
||||
for comp_id, cp in progress.component_progress.items():
|
||||
comp_list.append({
|
||||
"component_id": cp.component_id,
|
||||
"status": cp.status.value,
|
||||
"download_progress": cp.download_progress,
|
||||
"error_message": cp.error_message,
|
||||
})
|
||||
|
||||
return PM3ServiceResult(
|
||||
success=True,
|
||||
data={
|
||||
@@ -164,7 +176,9 @@ class UpdateService:
|
||||
"available_version": progress.available_version,
|
||||
"download_progress": progress.download_progress,
|
||||
"error_message": progress.error_message,
|
||||
"last_check": progress.last_check
|
||||
"last_check": progress.last_check,
|
||||
"active_component": progress.active_component,
|
||||
"components": comp_list,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -310,3 +324,151 @@ class UpdateService:
|
||||
details=str(e)
|
||||
)
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Component-level operations
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
async def get_installed_components(self) -> PM3ServiceResult:
|
||||
"""Get the installed component manifest.
|
||||
|
||||
Returns:
|
||||
PM3ServiceResult with component manifest data
|
||||
"""
|
||||
try:
|
||||
manifest = self.update_manager.get_manifest()
|
||||
components = {}
|
||||
for comp_id, comp in manifest.components.items():
|
||||
components[comp_id] = asdict(comp)
|
||||
|
||||
return PM3ServiceResult(
|
||||
success=True,
|
||||
data={
|
||||
"schema_version": manifest.schema_version,
|
||||
"system_version": manifest.system_version,
|
||||
"components": components,
|
||||
"plugins": manifest.plugins,
|
||||
"last_updated": manifest.last_updated,
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
return PM3ServiceResult(
|
||||
success=False,
|
||||
error=PM3ServiceError(
|
||||
code="manifest_error",
|
||||
message="Failed to get component manifest",
|
||||
details=str(e)
|
||||
)
|
||||
)
|
||||
|
||||
async def download_component(self, component_id: str) -> PM3ServiceResult:
|
||||
"""Download a specific component update.
|
||||
|
||||
Args:
|
||||
component_id: Component to download (pm3, frontend, backend, theme)
|
||||
|
||||
Returns:
|
||||
PM3ServiceResult indicating download success/failure
|
||||
"""
|
||||
try:
|
||||
success = await self.update_manager.download_component(component_id)
|
||||
return PM3ServiceResult(
|
||||
success=True,
|
||||
data={
|
||||
"message": f"Component {component_id} downloaded successfully",
|
||||
"component_id": component_id,
|
||||
"ready_to_install": True,
|
||||
}
|
||||
)
|
||||
except ValueError as e:
|
||||
return PM3ServiceResult(
|
||||
success=False,
|
||||
error=PM3ServiceError(
|
||||
code="component_not_available",
|
||||
message=str(e)
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
return PM3ServiceResult(
|
||||
success=False,
|
||||
error=PM3ServiceError(
|
||||
code="component_download_error",
|
||||
message=f"Error downloading {component_id}",
|
||||
details=str(e)
|
||||
)
|
||||
)
|
||||
|
||||
async def install_component(self, component_id: str) -> PM3ServiceResult:
|
||||
"""Install a downloaded component update.
|
||||
|
||||
Args:
|
||||
component_id: Component to install
|
||||
|
||||
Returns:
|
||||
PM3ServiceResult indicating install success/failure
|
||||
"""
|
||||
try:
|
||||
success = await self.update_manager.install_component(component_id)
|
||||
return PM3ServiceResult(
|
||||
success=True,
|
||||
data={
|
||||
"message": f"Component {component_id} installed successfully",
|
||||
"component_id": component_id,
|
||||
"requires_restart": component_id in (
|
||||
ComponentId.BACKEND, ComponentId.PM3
|
||||
),
|
||||
}
|
||||
)
|
||||
except ValueError as e:
|
||||
return PM3ServiceResult(
|
||||
success=False,
|
||||
error=PM3ServiceError(
|
||||
code="component_install_error",
|
||||
message=str(e)
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
return PM3ServiceResult(
|
||||
success=False,
|
||||
error=PM3ServiceError(
|
||||
code="component_install_error",
|
||||
message=f"Error installing {component_id}",
|
||||
details=str(e)
|
||||
)
|
||||
)
|
||||
|
||||
async def rollback_component(self, component_id: str) -> PM3ServiceResult:
|
||||
"""Rollback a component to its previous version.
|
||||
|
||||
Args:
|
||||
component_id: Component to rollback
|
||||
|
||||
Returns:
|
||||
PM3ServiceResult indicating rollback success/failure
|
||||
"""
|
||||
try:
|
||||
success = await self.update_manager.rollback_component(component_id)
|
||||
return PM3ServiceResult(
|
||||
success=True,
|
||||
data={
|
||||
"message": f"Component {component_id} rolled back successfully",
|
||||
"component_id": component_id,
|
||||
}
|
||||
)
|
||||
except ValueError as e:
|
||||
return PM3ServiceResult(
|
||||
success=False,
|
||||
error=PM3ServiceError(
|
||||
code="rollback_error",
|
||||
message=str(e)
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
return PM3ServiceResult(
|
||||
success=False,
|
||||
error=PM3ServiceError(
|
||||
code="rollback_error",
|
||||
message=f"Error rolling back {component_id}",
|
||||
details=str(e)
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user