CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
186 lines
6.1 KiB
Python
186 lines
6.1 KiB
Python
"""
|
|
Configuration for the artifact recombination phase.
|
|
|
|
This module defines the configuration schema for combining split artifacts
|
|
from the map phase into final package groups.
|
|
"""
|
|
|
|
import json
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
|
|
|
|
@dataclass
|
|
class ArchitectureGroup:
|
|
"""Defines a package group and its member architectures."""
|
|
|
|
display_name: str
|
|
architectures: list[str]
|
|
|
|
def __post_init__(self):
|
|
if not self.architectures:
|
|
raise ValueError(
|
|
f"Architecture group '{self.display_name}' must have at least one architecture"
|
|
)
|
|
|
|
# Validate architecture format (gfxXXXX)
|
|
for arch in self.architectures:
|
|
if not arch.startswith("gfx"):
|
|
raise ValueError(
|
|
f"Invalid architecture '{arch}': must start with 'gfx'"
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class ValidationRules:
|
|
"""Validation rules for the recombination process."""
|
|
|
|
error_on_duplicate_device_code: bool = True
|
|
verify_generic_artifacts_match: bool = False
|
|
error_on_missing_architecture: bool = False
|
|
|
|
|
|
@dataclass
|
|
class PackagingConfig:
|
|
"""
|
|
Configuration for artifact recombination.
|
|
|
|
This configuration determines how split artifacts from the map phase
|
|
are combined into final package groups.
|
|
"""
|
|
|
|
primary_shard: str
|
|
architecture_groups: dict[str, ArchitectureGroup]
|
|
validation: ValidationRules = field(default_factory=ValidationRules)
|
|
|
|
def __post_init__(self):
|
|
if not self.primary_shard:
|
|
raise ValueError("primary_shard must be specified")
|
|
|
|
if not self.architecture_groups:
|
|
raise ValueError("At least one architecture group must be defined")
|
|
|
|
@classmethod
|
|
def from_json(cls, json_path: Path) -> "PackagingConfig":
|
|
"""
|
|
Load configuration from a JSON file.
|
|
|
|
Args:
|
|
json_path: Path to JSON configuration file
|
|
|
|
Returns:
|
|
PackagingConfig instance
|
|
|
|
Raises:
|
|
FileNotFoundError: If configuration file doesn't exist
|
|
ValueError: If JSON is invalid or configuration is malformed
|
|
"""
|
|
if not json_path.exists():
|
|
raise FileNotFoundError(f"Configuration file not found: {json_path}")
|
|
|
|
if json_path.stat().st_size == 0:
|
|
raise ValueError(f"Configuration file is empty: {json_path}")
|
|
|
|
try:
|
|
with open(json_path) as f:
|
|
data = json.load(f)
|
|
except json.JSONDecodeError as e:
|
|
raise ValueError(f"Invalid JSON in {json_path}: {e}") from e
|
|
except OSError as e:
|
|
raise RuntimeError(
|
|
f"Cannot read configuration file {json_path}: {e}"
|
|
) from e
|
|
|
|
# Parse architecture groups
|
|
groups = {}
|
|
if "architecture_groups" not in data:
|
|
raise ValueError("Missing required field: architecture_groups")
|
|
|
|
for group_name, group_data in data["architecture_groups"].items():
|
|
if not isinstance(group_data, dict):
|
|
raise ValueError(f"Architecture group '{group_name}' must be an object")
|
|
|
|
if "architectures" not in group_data:
|
|
raise ValueError(
|
|
f"Architecture group '{group_name}' missing 'architectures' field"
|
|
)
|
|
|
|
display_name = group_data.get("display_name", group_name)
|
|
architectures = group_data["architectures"]
|
|
|
|
if not isinstance(architectures, list):
|
|
raise ValueError(
|
|
f"Architecture group '{group_name}' architectures must be a list"
|
|
)
|
|
|
|
groups[group_name] = ArchitectureGroup(
|
|
display_name=display_name, architectures=architectures
|
|
)
|
|
|
|
# Parse validation rules
|
|
validation = ValidationRules()
|
|
if "validation" in data:
|
|
val_data = data["validation"]
|
|
if not isinstance(val_data, dict):
|
|
raise ValueError("'validation' field must be an object")
|
|
|
|
validation = ValidationRules(
|
|
error_on_duplicate_device_code=val_data.get(
|
|
"error_on_duplicate_device_code", True
|
|
),
|
|
verify_generic_artifacts_match=val_data.get(
|
|
"verify_generic_artifacts_match", False
|
|
),
|
|
error_on_missing_architecture=val_data.get(
|
|
"error_on_missing_architecture", False
|
|
),
|
|
)
|
|
|
|
# Get primary shard
|
|
if "primary_shard" not in data:
|
|
raise ValueError("Missing required field: primary_shard")
|
|
|
|
primary_shard = data["primary_shard"]
|
|
if not isinstance(primary_shard, str):
|
|
raise ValueError("'primary_shard' must be a string")
|
|
|
|
return cls(
|
|
primary_shard=primary_shard,
|
|
architecture_groups=groups,
|
|
validation=validation,
|
|
)
|
|
|
|
def to_json(self, json_path: Path) -> None:
|
|
"""
|
|
Write configuration to a JSON file.
|
|
|
|
Args:
|
|
json_path: Path where JSON file will be written
|
|
"""
|
|
# Build architecture groups dict
|
|
groups_dict = {}
|
|
for group_name, group in self.architecture_groups.items():
|
|
groups_dict[group_name] = {
|
|
"display_name": group.display_name,
|
|
"architectures": group.architectures,
|
|
}
|
|
|
|
data = {
|
|
"primary_shard": self.primary_shard,
|
|
"architecture_groups": groups_dict,
|
|
"validation": {
|
|
"error_on_duplicate_device_code": self.validation.error_on_duplicate_device_code,
|
|
"verify_generic_artifacts_match": self.validation.verify_generic_artifacts_match,
|
|
"error_on_missing_architecture": self.validation.error_on_missing_architecture,
|
|
},
|
|
}
|
|
|
|
with open(json_path, "w") as f:
|
|
json.dump(data, f, indent=2)
|
|
|
|
# Validate output
|
|
if not json_path.exists():
|
|
raise RuntimeError(f"Failed to write configuration file: {json_path}")
|
|
if json_path.stat().st_size == 0:
|
|
raise RuntimeError(f"Written configuration file is empty: {json_path}")
|