899 lines
28 KiB
Plaintext
899 lines
28 KiB
Plaintext
#!/usr/bin/env nu
|
|
|
|
# Platform distribution preparation tool - prepares platform services for distribution
|
|
#
|
|
# Prepares:
|
|
# - Rust platform binaries (orchestrator, control-center, etc.)
|
|
# - Container images and deployment configurations
|
|
# - Service definitions and systemd units
|
|
# - Platform-specific installation packages
|
|
# - Cross-compilation for multiple architectures
|
|
|
|
use std log
|
|
|
|
def main [
|
|
--source-root: string = "" # Source root directory (auto-detected if empty)
|
|
--output-dir: string = "dist/platform" # Output directory for platform distribution
|
|
--target-platforms: string = "linux-amd64,macos-amd64,windows-amd64" # Target platforms
|
|
--build-mode: string = "release" # Build mode: debug, release, optimized
|
|
--strip-symbols: bool = true # Strip debug symbols from release builds
|
|
--upx-compress: bool = false # Compress binaries with UPX
|
|
--create-containers: bool = false # Create container images
|
|
--generate-services: bool = true # Generate service definitions
|
|
--sign-binaries: bool = false # Sign binaries (requires signing keys)
|
|
--parallel-builds: bool = true # Build platforms in parallel
|
|
--verbose: bool = false # Enable verbose logging
|
|
] -> record {
|
|
|
|
let repo_root = if $source_root == "" {
|
|
($env.PWD | path dirname | path dirname | path dirname)
|
|
} else {
|
|
($source_root | path expand)
|
|
}
|
|
|
|
let target_platforms_list = ($target_platforms | split row "," | each { str trim })
|
|
|
|
let platform_config = {
|
|
source_root: $repo_root
|
|
output_dir: ($output_dir | path expand)
|
|
target_platforms: $target_platforms_list
|
|
build_mode: $build_mode
|
|
strip_symbols: $strip_symbols
|
|
upx_compress: $upx_compress
|
|
create_containers: $create_containers
|
|
generate_services: $generate_services
|
|
sign_binaries: $sign_binaries
|
|
parallel_builds: $parallel_builds
|
|
verbose: $verbose
|
|
}
|
|
|
|
log info $"Starting platform distribution preparation with config: ($platform_config)"
|
|
|
|
# Ensure output directory exists
|
|
mkdir ($platform_config.output_dir)
|
|
|
|
let preparation_results = []
|
|
|
|
try {
|
|
# Phase 1: Discover platform components
|
|
let discovery_result = discover_platform_components $platform_config
|
|
|
|
let preparation_results = ($preparation_results | append { phase: "discovery", result: $discovery_result })
|
|
|
|
if $discovery_result.status != "success" {
|
|
log error $"Platform component discovery failed: ($discovery_result.reason)"
|
|
exit 1
|
|
}
|
|
|
|
# Phase 2: Build platform binaries
|
|
let build_result = build_platform_binaries $platform_config $discovery_result
|
|
|
|
let preparation_results = ($preparation_results | append { phase: "build", result: $build_result })
|
|
|
|
if $build_result.status != "success" and $build_result.status != "partial" {
|
|
log error $"Platform binary build failed: ($build_result.reason)"
|
|
exit 1
|
|
}
|
|
|
|
# Phase 3: Post-process binaries
|
|
let processing_result = post_process_binaries $platform_config $build_result
|
|
|
|
let preparation_results = ($preparation_results | append { phase: "processing", result: $processing_result })
|
|
|
|
# Phase 4: Generate service definitions
|
|
let services_result = if $platform_config.generate_services {
|
|
generate_service_definitions $platform_config $build_result
|
|
} else {
|
|
{ status: "skipped", reason: "service generation disabled" }
|
|
}
|
|
|
|
let preparation_results = ($preparation_results | append { phase: "services", result: $services_result })
|
|
|
|
# Phase 5: Create container images
|
|
let containers_result = if $platform_config.create_containers {
|
|
create_container_images $platform_config $build_result
|
|
} else {
|
|
{ status: "skipped", reason: "container creation disabled" }
|
|
}
|
|
|
|
let preparation_results = ($preparation_results | append { phase: "containers", result: $containers_result })
|
|
|
|
# Phase 6: Generate platform metadata
|
|
let metadata_result = generate_platform_metadata $platform_config $preparation_results
|
|
|
|
let preparation_results = ($preparation_results | append { phase: "metadata", result: $metadata_result })
|
|
|
|
let summary = {
|
|
source_root: $platform_config.source_root
|
|
output_directory: $platform_config.output_dir
|
|
target_platforms: ($platform_config.target_platforms | length)
|
|
successful_phases: ($preparation_results | where {|r| $r.result.status == "success"} | length)
|
|
total_phases: ($preparation_results | length)
|
|
binaries_built: ($build_result.successful_builds)
|
|
total_size: (get_directory_size $platform_config.output_dir)
|
|
platform_config: $platform_config
|
|
phases: $preparation_results
|
|
}
|
|
|
|
log info $"Platform distribution preparation completed - ($summary.binaries_built) binaries built for ($summary.target_platforms) platforms"
|
|
|
|
return $summary
|
|
|
|
} catch {|err|
|
|
log error $"Platform distribution preparation failed: ($err.msg)"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# Discover platform components in the source tree
|
|
def discover_platform_components [platform_config: record] -> record {
|
|
log info "Discovering platform components..."
|
|
|
|
let start_time = (date now)
|
|
|
|
try {
|
|
# Define platform project locations
|
|
let rust_projects = [
|
|
{
|
|
name: "orchestrator"
|
|
path: ($platform_config.source_root | path join "orchestrator")
|
|
binary: "provisioning-orchestrator"
|
|
description: "Main orchestration service"
|
|
required: true
|
|
},
|
|
{
|
|
name: "control-center"
|
|
path: ($platform_config.source_root | path join "control-center")
|
|
binary: "control-center"
|
|
description: "Control center API service"
|
|
required: true
|
|
},
|
|
{
|
|
name: "control-center-ui"
|
|
path: ($platform_config.source_root | path join "control-center-ui")
|
|
binary: "control-center-ui"
|
|
description: "Control center web UI"
|
|
required: false
|
|
},
|
|
{
|
|
name: "mcp-server"
|
|
path: ($platform_config.source_root | path join "provisioning" "mcp-server-rust")
|
|
binary: "mcp-server-rust"
|
|
description: "MCP integration server"
|
|
required: false
|
|
}
|
|
]
|
|
|
|
# Validate project existence and Cargo.toml files
|
|
let mut validated_projects = []
|
|
let mut missing_projects = []
|
|
|
|
for project in $rust_projects {
|
|
let cargo_file = ($project.path | path join "Cargo.toml")
|
|
|
|
if ($project.path | path exists) and ($cargo_file | path exists) {
|
|
# Parse Cargo.toml to get project information
|
|
let cargo_data = (open $cargo_file)
|
|
let project_info = ($project | insert version $cargo_data.package.version | insert cargo_data $cargo_data)
|
|
$validated_projects = ($validated_projects | append $project_info)
|
|
} else {
|
|
if $project.required {
|
|
$missing_projects = ($missing_projects | append $project.name)
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($missing_projects | length) > 0 {
|
|
return {
|
|
status: "failed"
|
|
reason: $"Missing required projects: ($missing_projects | str join ', ')"
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
|
|
# Check build environment
|
|
let build_env = validate_build_environment $platform_config
|
|
|
|
{
|
|
status: "success"
|
|
rust_projects: $validated_projects
|
|
missing_projects: $missing_projects
|
|
total_projects: ($validated_projects | length)
|
|
build_environment: $build_env
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Validate build environment
|
|
def validate_build_environment [platform_config: record] -> record {
|
|
let mut build_tools = {}
|
|
|
|
# Check Rust toolchain
|
|
let rust_version = try {
|
|
rustc --version | str trim
|
|
} catch {
|
|
"not available"
|
|
}
|
|
|
|
let cargo_version = try {
|
|
cargo --version | str trim
|
|
} catch {
|
|
"not available"
|
|
}
|
|
|
|
$build_tools = ($build_tools | insert rust $rust_version | insert cargo $cargo_version)
|
|
|
|
# Check for target platforms
|
|
let mut target_availability = {}
|
|
|
|
for platform in $platform_config.target_platforms {
|
|
let target_triple = get_rust_target_triple $platform
|
|
|
|
let target_installed = try {
|
|
rustup target list --installed | lines | any {|line| $line | str contains $target_triple}
|
|
} catch {
|
|
false
|
|
}
|
|
|
|
$target_availability = ($target_availability | insert $platform $target_installed)
|
|
}
|
|
|
|
# Check optional tools
|
|
let upx_available = try {
|
|
upx --version | complete | get exit_code | $in == 0
|
|
} catch {
|
|
false
|
|
}
|
|
|
|
let strip_available = try {
|
|
strip --version | complete | get exit_code | $in == 0
|
|
} catch {
|
|
false
|
|
}
|
|
|
|
let docker_available = try {
|
|
docker --version | complete | get exit_code | $in == 0
|
|
} catch {
|
|
false
|
|
}
|
|
|
|
{
|
|
build_tools: $build_tools
|
|
target_availability: $target_availability
|
|
optional_tools: {
|
|
upx: $upx_available
|
|
strip: $strip_available
|
|
docker: $docker_available
|
|
}
|
|
rust_ready: ($rust_version != "not available" and $cargo_version != "not available")
|
|
}
|
|
}
|
|
|
|
# Build platform binaries for all target platforms
|
|
def build_platform_binaries [
|
|
platform_config: record
|
|
discovery_result: record
|
|
] -> record {
|
|
log info "Building platform binaries..."
|
|
|
|
let start_time = (date now)
|
|
|
|
try {
|
|
# Build binaries for each platform
|
|
let build_results = if $platform_config.parallel_builds {
|
|
build_platforms_parallel $platform_config $discovery_result
|
|
} else {
|
|
build_platforms_sequential $platform_config $discovery_result
|
|
}
|
|
|
|
let successful_builds = ($build_results | where status == "success" | length)
|
|
let total_builds = ($build_results | length)
|
|
let failed_builds = ($build_results | where status == "failed")
|
|
|
|
let status = if $successful_builds == 0 {
|
|
"failed"
|
|
} else if $successful_builds < $total_builds {
|
|
"partial"
|
|
} else {
|
|
"success"
|
|
}
|
|
|
|
{
|
|
status: $status
|
|
successful_builds: $successful_builds
|
|
total_builds: $total_builds
|
|
failed_builds: ($failed_builds | length)
|
|
build_results: $build_results
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Build platforms in parallel (simplified sequential for now)
|
|
def build_platforms_parallel [
|
|
platform_config: record
|
|
discovery_result: record
|
|
] -> list {
|
|
build_platforms_sequential $platform_config $discovery_result
|
|
}
|
|
|
|
# Build platforms sequentially
|
|
def build_platforms_sequential [
|
|
platform_config: record
|
|
discovery_result: record
|
|
] -> list {
|
|
let mut all_build_results = []
|
|
|
|
for platform in $platform_config.target_platforms {
|
|
for project in $discovery_result.rust_projects {
|
|
let build_result = build_single_binary $platform $project $platform_config
|
|
|
|
$all_build_results = ($all_build_results | append $build_result)
|
|
}
|
|
}
|
|
|
|
return $all_build_results
|
|
}
|
|
|
|
# Build a single binary for a specific platform
|
|
def build_single_binary [
|
|
platform: string
|
|
project: record
|
|
platform_config: record
|
|
] -> record {
|
|
log info $"Building ($project.name) for ($platform)..."
|
|
|
|
let start_time = (date now)
|
|
let target_triple = get_rust_target_triple $platform
|
|
|
|
try {
|
|
cd $project.path
|
|
|
|
# Build cargo command
|
|
let mut cargo_cmd = ["cargo", "build"]
|
|
|
|
# Add build mode
|
|
if $platform_config.build_mode == "release" or $platform_config.build_mode == "optimized" {
|
|
$cargo_cmd = ($cargo_cmd | append "--release")
|
|
}
|
|
|
|
# Add target platform
|
|
$cargo_cmd = ($cargo_cmd | append ["--target", $target_triple])
|
|
|
|
# Add optimization flags for optimized builds
|
|
if $platform_config.build_mode == "optimized" {
|
|
$env.RUSTFLAGS = "-C target-cpu=native -C opt-level=3 -C lto=fat"
|
|
}
|
|
|
|
# Execute build
|
|
if $platform_config.verbose {
|
|
log info $"Running: ($cargo_cmd | str join ' ')"
|
|
}
|
|
|
|
let build_result = (run-external --redirect-combine $cargo_cmd.0 ...$cargo_cmd.1.. | complete)
|
|
|
|
if $build_result.exit_code == 0 {
|
|
# Determine binary path
|
|
let profile = if $platform_config.build_mode == "debug" { "debug" } else { "release" }
|
|
let binary_path = ($project.path | path join "target" $target_triple $profile $project.binary)
|
|
|
|
# Add .exe extension for Windows
|
|
let final_binary_path = if ($platform | str contains "windows") {
|
|
$binary_path + ".exe"
|
|
} else {
|
|
$binary_path
|
|
}
|
|
|
|
if ($final_binary_path | path exists) {
|
|
# Copy to output directory with platform suffix
|
|
let output_name = $"($project.binary)-($platform)"
|
|
let output_path = ($platform_config.output_dir | path join $output_name)
|
|
|
|
cp $final_binary_path $output_path
|
|
|
|
let binary_size = (ls $output_path | get 0.size)
|
|
|
|
{
|
|
project: $project.name
|
|
platform: $platform
|
|
target: $target_triple
|
|
status: "success"
|
|
binary_path: $output_path
|
|
binary_size: $binary_size
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
} else {
|
|
{
|
|
project: $project.name
|
|
platform: $platform
|
|
target: $target_triple
|
|
status: "failed"
|
|
reason: $"binary not found at ($final_binary_path)"
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
} else {
|
|
{
|
|
project: $project.name
|
|
platform: $platform
|
|
target: $target_triple
|
|
status: "failed"
|
|
reason: $build_result.stderr
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
project: $project.name
|
|
platform: $platform
|
|
target: $target_triple
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Get Rust target triple for platform
|
|
def get_rust_target_triple [platform: string] -> string {
|
|
match $platform {
|
|
"linux-amd64" => "x86_64-unknown-linux-gnu"
|
|
"linux-arm64" => "aarch64-unknown-linux-gnu"
|
|
"macos-amd64" => "x86_64-apple-darwin"
|
|
"macos-arm64" => "aarch64-apple-darwin"
|
|
"windows-amd64" => "x86_64-pc-windows-gnu"
|
|
"windows-arm64" => "aarch64-pc-windows-msvc"
|
|
_ => $platform # Assume it's already a target triple
|
|
}
|
|
}
|
|
|
|
# Post-process binaries (strip, compress, sign)
|
|
def post_process_binaries [
|
|
platform_config: record
|
|
build_result: record
|
|
] -> record {
|
|
log info "Post-processing binaries..."
|
|
|
|
let start_time = (date now)
|
|
|
|
try {
|
|
let successful_builds = ($build_result.build_results | where status == "success")
|
|
let mut processing_results = []
|
|
|
|
for build in $successful_builds {
|
|
let processing_result = process_single_binary $build $platform_config
|
|
|
|
$processing_results = ($processing_results | append $processing_result)
|
|
}
|
|
|
|
let successful_processing = ($processing_results | where status == "success" | length)
|
|
let total_processing = ($processing_results | length)
|
|
|
|
{
|
|
status: (if $successful_processing == $total_processing { "success" } else { "partial" })
|
|
processed_binaries: $successful_processing
|
|
total_binaries: $total_processing
|
|
processing_results: $processing_results
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Process a single binary
|
|
def process_single_binary [
|
|
build: record
|
|
platform_config: record
|
|
] -> record {
|
|
let mut processing_steps = []
|
|
let binary_path = $build.binary_path
|
|
|
|
try {
|
|
let original_size = $build.binary_size
|
|
|
|
# Strip debug symbols if requested
|
|
if $platform_config.strip_symbols and not ($build.platform | str contains "windows") {
|
|
let strip_result = strip_binary_symbols $binary_path $platform_config
|
|
|
|
$processing_steps = ($processing_steps | append { step: "strip", result: $strip_result })
|
|
}
|
|
|
|
# UPX compress if requested
|
|
let mut final_size = $original_size
|
|
|
|
if $platform_config.upx_compress {
|
|
let upx_result = upx_compress_binary $binary_path $platform_config
|
|
|
|
$processing_steps = ($processing_steps | append { step: "upx", result: $upx_result })
|
|
|
|
if $upx_result.status == "success" {
|
|
$final_size = $upx_result.compressed_size
|
|
}
|
|
}
|
|
|
|
# Sign binary if requested
|
|
if $platform_config.sign_binaries {
|
|
let sign_result = sign_binary $binary_path $platform_config
|
|
|
|
$processing_steps = ($processing_steps | append { step: "sign", result: $sign_result })
|
|
}
|
|
|
|
# Update final size
|
|
let current_size = (ls $binary_path | get 0.size)
|
|
let compression_ratio = (($current_size | into float) / ($original_size | into float) * 100)
|
|
|
|
{
|
|
project: $build.project
|
|
platform: $build.platform
|
|
binary_path: $binary_path
|
|
status: "success"
|
|
original_size: $original_size
|
|
final_size: $current_size
|
|
compression_ratio: $compression_ratio
|
|
processing_steps: $processing_steps
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
project: $build.project
|
|
platform: $build.platform
|
|
binary_path: $binary_path
|
|
status: "failed"
|
|
reason: $err.msg
|
|
processing_steps: $processing_steps
|
|
}
|
|
}
|
|
}
|
|
|
|
# Strip debug symbols from binary
|
|
def strip_binary_symbols [binary_path: string, platform_config: record] -> record {
|
|
try {
|
|
if $platform_config.verbose {
|
|
log info $"Stripping symbols from: ($binary_path)"
|
|
}
|
|
|
|
let strip_result = (strip $binary_path | complete)
|
|
|
|
if $strip_result.exit_code == 0 {
|
|
{ status: "success", stripped: true }
|
|
} else {
|
|
{ status: "failed", reason: $strip_result.stderr }
|
|
}
|
|
|
|
} catch {|err|
|
|
{ status: "failed", reason: $err.msg }
|
|
}
|
|
}
|
|
|
|
# Compress binary with UPX
|
|
def upx_compress_binary [binary_path: string, platform_config: record] -> record {
|
|
try {
|
|
if $platform_config.verbose {
|
|
log info $"UPX compressing: ($binary_path)"
|
|
}
|
|
|
|
let original_size = (ls $binary_path | get 0.size)
|
|
|
|
let upx_result = (upx --best $binary_path | complete)
|
|
|
|
if $upx_result.exit_code == 0 {
|
|
let compressed_size = (ls $binary_path | get 0.size)
|
|
let ratio = (($compressed_size | into float) / ($original_size | into float) * 100)
|
|
|
|
{
|
|
status: "success"
|
|
compressed: true
|
|
original_size: $original_size
|
|
compressed_size: $compressed_size
|
|
compression_ratio: $ratio
|
|
}
|
|
} else {
|
|
{ status: "failed", reason: $upx_result.stderr }
|
|
}
|
|
|
|
} catch {|err|
|
|
{ status: "failed", reason: $err.msg }
|
|
}
|
|
}
|
|
|
|
# Sign binary (placeholder - would need actual signing implementation)
|
|
def sign_binary [binary_path: string, platform_config: record] -> record {
|
|
log warning "Binary signing not implemented - skipping"
|
|
{ status: "skipped", reason: "signing not implemented" }
|
|
}
|
|
|
|
# Generate service definitions
|
|
def generate_service_definitions [
|
|
platform_config: record
|
|
build_result: record
|
|
] -> record {
|
|
log info "Generating service definitions..."
|
|
|
|
let start_time = (date now)
|
|
|
|
try {
|
|
let services_dir = ($platform_config.output_dir | path join "services")
|
|
mkdir $services_dir
|
|
|
|
let successful_builds = ($build_result.build_results | where status == "success")
|
|
let mut generated_services = []
|
|
|
|
# Generate systemd service files
|
|
for build in $successful_builds {
|
|
if $build.platform | str starts-with "linux" {
|
|
let systemd_service = generate_systemd_service $build $platform_config
|
|
|
|
let service_file = ($services_dir | path join $"($build.project).service")
|
|
$systemd_service | save $service_file
|
|
|
|
$generated_services = ($generated_services | append {
|
|
project: $build.project
|
|
platform: $build.platform
|
|
service_type: "systemd"
|
|
service_file: $service_file
|
|
})
|
|
}
|
|
}
|
|
|
|
# Generate Docker Compose definitions
|
|
let docker_compose = generate_docker_compose $successful_builds $platform_config
|
|
|
|
let compose_file = ($services_dir | path join "docker-compose.yml")
|
|
$docker_compose | save $compose_file
|
|
|
|
{
|
|
status: "success"
|
|
services_generated: ($generated_services | length)
|
|
services_directory: $services_dir
|
|
generated_services: $generated_services
|
|
docker_compose: $compose_file
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Generate systemd service file
|
|
def generate_systemd_service [build: record, platform_config: record] -> string {
|
|
$"[Unit]
|
|
Description=Provisioning ($build.project | str title-case) Service
|
|
After=network.target
|
|
Wants=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=provisioning
|
|
Group=provisioning
|
|
ExecStart=/usr/local/bin/($build.project | str replace "_" "-")
|
|
Restart=always
|
|
RestartSec=5
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
SyslogIdentifier=provisioning-($build.project)
|
|
|
|
# Security settings
|
|
NoNewPrivileges=true
|
|
PrivateTmp=true
|
|
ProtectSystem=strict
|
|
ProtectHome=true
|
|
ReadWritePaths=/var/lib/provisioning /var/log/provisioning
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
"
|
|
}
|
|
|
|
# Generate Docker Compose file
|
|
def generate_docker_compose [builds: list, platform_config: record] -> string {
|
|
let mut services = []
|
|
|
|
for build in $builds {
|
|
let service_def = $" ($build.project | str replace "_" "-"):
|
|
image: provisioning/($build.project):latest
|
|
restart: unless-stopped
|
|
ports:
|
|
- \"8080:8080\" # Adjust port as needed
|
|
volumes:
|
|
- provisioning-data:/data
|
|
- ./config:/etc/provisioning:ro
|
|
environment:
|
|
- PROVISIONING_ENV=production
|
|
healthcheck:
|
|
test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:8080/health\"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3"
|
|
|
|
$services = ($services | append $service_def)
|
|
}
|
|
|
|
let compose_content = $"version: '3.8'
|
|
|
|
services:
|
|
($services | str join "\n\n")
|
|
|
|
volumes:
|
|
provisioning-data:
|
|
driver: local
|
|
|
|
networks:
|
|
default:
|
|
name: provisioning
|
|
"
|
|
|
|
return $compose_content
|
|
}
|
|
|
|
# Create container images
|
|
def create_container_images [
|
|
platform_config: record
|
|
build_result: record
|
|
] -> record {
|
|
log info "Creating container images..."
|
|
|
|
let start_time = (date now)
|
|
|
|
# Container creation would use the build-containers.nu tool
|
|
let containers_result = try {
|
|
nu ($platform_config.source_root | path join "src" "tools" "package" "build-containers.nu")
|
|
--dist-dir ($platform_config.output_dir | path dirname)
|
|
--tag-prefix "provisioning"
|
|
--platforms "linux/amd64"
|
|
--verbose:$platform_config.verbose
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
}
|
|
}
|
|
|
|
{
|
|
status: $containers_result.status
|
|
containers_created: (if "successful_builds" in ($containers_result | columns) { $containers_result.successful_builds } else { 0 })
|
|
container_results: $containers_result
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
|
|
# Generate platform metadata
|
|
def generate_platform_metadata [
|
|
platform_config: record
|
|
preparation_results: list
|
|
] -> record {
|
|
log info "Generating platform metadata..."
|
|
|
|
let start_time = (date now)
|
|
|
|
try {
|
|
let metadata = {
|
|
name: "provisioning-platform"
|
|
version: (detect_version $platform_config.source_root)
|
|
type: "platform-distribution"
|
|
created_at: (date now)
|
|
created_by: "platform-distribution-tool"
|
|
build_configuration: $platform_config
|
|
target_platforms: $platform_config.target_platforms
|
|
preparation_phases: ($preparation_results | each {|r|
|
|
{
|
|
phase: $r.phase
|
|
status: $r.result.status
|
|
duration: (if "duration" in ($r.result | columns) { $r.result.duration } else { 0 })
|
|
}
|
|
})
|
|
build_statistics: {
|
|
total_phases: ($preparation_results | length)
|
|
successful_phases: ($preparation_results | where {|r| $r.result.status == "success"} | length)
|
|
distribution_size: (get_directory_size $platform_config.output_dir)
|
|
}
|
|
}
|
|
|
|
let metadata_file = ($platform_config.output_dir | path join "platform-metadata.json")
|
|
$metadata | to json | save $metadata_file
|
|
|
|
{
|
|
status: "success"
|
|
metadata_file: $metadata_file
|
|
metadata: $metadata
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Detect version from git or other sources
|
|
def detect_version [repo_root: string] -> string {
|
|
cd $repo_root
|
|
|
|
try {
|
|
let git_version = (git describe --tags --always --dirty 2>/dev/null | str trim)
|
|
if $git_version != "" {
|
|
return ($git_version | str replace "^v" "")
|
|
}
|
|
|
|
return $"dev-(date now | format date '%Y%m%d')"
|
|
} catch {
|
|
return "unknown"
|
|
}
|
|
}
|
|
|
|
# Get directory size helper
|
|
def get_directory_size [dir: string] -> int {
|
|
if not ($dir | path exists) {
|
|
return 0
|
|
}
|
|
|
|
try {
|
|
find $dir -type f | each {|file| ls $file | get 0.size } | math sum | if $in == null { 0 } else { $in }
|
|
} catch {
|
|
0
|
|
}
|
|
}
|
|
|
|
# Show platform distribution status
|
|
def "main status" [] {
|
|
let repo_root = ($env.PWD | path dirname | path dirname | path dirname)
|
|
let version = (detect_version $repo_root)
|
|
|
|
# Check for platform components
|
|
let orchestrator_exists = (($repo_root | path join "orchestrator" "Cargo.toml") | path exists)
|
|
let control_center_exists = (($repo_root | path join "control-center" "Cargo.toml") | path exists)
|
|
|
|
let build_env = validate_build_environment {
|
|
target_platforms: ["linux-amd64", "macos-amd64", "windows-amd64"]
|
|
}
|
|
|
|
{
|
|
repository: $repo_root
|
|
version: $version
|
|
platform_components: {
|
|
orchestrator: $orchestrator_exists
|
|
control_center: $control_center_exists
|
|
}
|
|
build_environment: $build_env
|
|
ready_for_build: ($build_env.rust_ready and $orchestrator_exists and $control_center_exists)
|
|
supported_platforms: ["linux-amd64", "linux-arm64", "macos-amd64", "macos-arm64", "windows-amd64"]
|
|
}
|
|
}
|
|
|
|
# Quick platform build for single target
|
|
def "main quick" [
|
|
--platform: string = "linux-amd64" # Single platform to build
|
|
--output-dir: string = "dist/platform" # Output directory
|
|
] {
|
|
main --target-platforms $platform --output-dir $output_dir --parallel-builds:false
|
|
} |