provisioning/tools/distribution/create-installer.nu

254 lines
8.8 KiB
Plaintext
Raw Normal View History

2025-10-07 11:12:02 +01:00
#!/usr/bin/env nu
# Module: Installer Creation Orchestrator
# Purpose: Orchestrates platform-specific installer generation with analysis, creation, validation
# Dependencies: installer_metadata, installer_generator, installer_validator, installer_utilities
2025-10-07 11:12:02 +01:00
use std log
# Import refactored modules
use ./installer_metadata.nu *
use ./installer_generator.nu *
use ./installer_validator.nu *
use ./installer_utilities.nu *
2025-10-07 11:12:02 +01:00
def main [
--distribution-path: string # Path to distribution to create installer for (required)
--output-dir: string = "installers" # Output directory for installers
--installer-types: string = "shell,package" # Installer types: shell, package, gui, all
--platforms: string = "linux,macos,windows" # Target platforms
--include-services = true # Include service installation
--create-uninstaller = true # Create uninstall scripts
--sign-packages = false # Sign installation packages
--validate-installer = true # Validate generated installers
2025-10-07 11:12:02 +01:00
--compression: string = "gzip" # Compression method for packages
--verbose # Enable verbose logging
] {
2025-10-07 11:12:02 +01:00
if $distribution_path == "" {
log error "Distribution path is required"
exit 1
}
let dist_root = ($distribution_path | path expand)
if not ($dist_root | path exists) {
log error $"Distribution path does not exist: ($dist_root)"
exit 1
}
let installer_types_list = if $installer_types == "all" {
["shell", "package", "gui"]
} else {
($installer_types | split row "," | each { str trim })
}
let platforms_list = ($platforms | split row "," | each { str trim })
let installer_config = {
distribution_path: $dist_root
output_dir: ($output_dir | path expand)
installer_types: $installer_types_list
platforms: $platforms_list
include_services: $include_services
create_uninstaller: $create_uninstaller
sign_packages: $sign_packages
validate_installer: $validate_installer
compression: $compression
verbose: $verbose
}
log info $"Starting installer creation with config: ($installer_config)"
# Ensure output directory exists
mkdir ($installer_config.output_dir)
let creation_results = []
let result = (do {
2025-10-07 11:12:02 +01:00
# Phase 1: Analyze distribution
let analysis_result = analyze_distribution $installer_config
let creation_results = ($creation_results | append { phase: "analysis", result: $analysis_result })
if $analysis_result.status != "success" {
log error $"Distribution analysis failed: ($analysis_result.reason)"
exit 1
}
# Phase 2: Create shell installers
let shell_result = if "shell" in $installer_config.installer_types {
create_shell_installers $installer_config $analysis_result
} else {
{ status: "skipped", reason: "shell installers not requested" }
}
let creation_results = ($creation_results | append { phase: "shell", result: $shell_result })
# Phase 3: Create package installers
let package_result = if "package" in $installer_config.installer_types {
create_package_installers $installer_config $analysis_result
} else {
{ status: "skipped", reason: "package installers not requested" }
}
let creation_results = ($creation_results | append { phase: "package", result: $package_result })
# Phase 4: Create GUI installers
let gui_result = if "gui" in $installer_config.installer_types {
create_gui_installers $installer_config $analysis_result
} else {
{ status: "skipped", reason: "GUI installers not requested" }
}
let creation_results = ($creation_results | append { phase: "gui", result: $gui_result })
# Phase 5: Create uninstallers
let uninstall_result = if $installer_config.create_uninstaller {
create_uninstall_scripts $installer_config $analysis_result
} else {
{ status: "skipped", reason: "uninstaller creation disabled" }
}
let creation_results = ($creation_results | append { phase: "uninstall", result: $uninstall_result })
# Phase 6: Validate installers
let validation_result = if $installer_config.validate_installer {
validate_installers $installer_config $creation_results
} else {
{ status: "skipped", reason: "installer validation disabled" }
}
let creation_results = ($creation_results | append { phase: "validation", result: $validation_result })
let summary = {
distribution_path: $installer_config.distribution_path
output_directory: $installer_config.output_dir
installer_types: ($installer_config.installer_types | length)
platforms: ($installer_config.platforms | length)
successful_phases: ($creation_results | where {|r| $r.result.status == "success"} | length)
total_phases: ($creation_results | length)
installers_created: (count_created_installers $creation_results)
installer_config: $installer_config
phases: $creation_results
}
log info $"Installer creation completed - ($summary.installers_created) installers created"
$summary
} | complete)
2025-10-07 11:12:02 +01:00
if $result.exit_code != 0 {
log error $"Installer creation failed: ($result.stderr)"
2025-10-07 11:12:02 +01:00
exit 1
}
$result.stdout
2025-10-07 11:12:02 +01:00
}
# Analysis orchestrator - coordinates metadata analysis
def analyze_distribution [installer_config: record] {
2025-10-07 11:12:02 +01:00
log info "Analyzing distribution structure..."
let start_time = (date now)
let result = (do {
2025-10-07 11:12:02 +01:00
let dist_path = $installer_config.distribution_path
# Detect distribution type and structure
let dist_info = {
is_archive: (($dist_path | path type) == "file")
is_directory: (($dist_path | path type) == "dir")
name: ($dist_path | path basename)
}
# If it's an archive, we need to extract it temporarily for analysis
let analysis_path = if $dist_info.is_archive {
extract_distribution_for_analysis $dist_path $installer_config
} else {
$dist_path
}
# Analyze distribution contents
let components = analyze_distribution_components $analysis_path
# Detect version information
let version_info = detect_distribution_version $analysis_path
# Analyze installation requirements
let requirements = analyze_installation_requirements $analysis_path $components
{
status: "success"
distribution_info: $dist_info
analysis_path: $analysis_path
components: $components
version_info: $version_info
requirements: $requirements
duration: ((date now) - $start_time)
}
} | complete)
2025-10-07 11:12:02 +01:00
if $result.exit_code != 0 {
2025-10-07 11:12:02 +01:00
{
status: "failed"
reason: $result.stderr
2025-10-07 11:12:02 +01:00
duration: ((date now) - $start_time)
}
} else {
$result.stdout
2025-10-07 11:12:02 +01:00
}
}
# Show installer creation status
def "main status" [distribution_path: string = ""] {
if $distribution_path == "" {
return {
error: "distribution path required"
usage: "main status <distribution-path>"
supported_platforms: ["linux", "macos", "windows"]
installer_types: ["shell", "package", "gui"]
}
}
let dist_path = ($distribution_path | path expand)
if not ($dist_path | path exists) {
return {
error: "distribution path does not exist"
path: $dist_path
}
}
# Quick analysis of distribution
let dist_info = {
path: $dist_path
type: ($dist_path | path type)
name: ($dist_path | path basename)
size: (get_directory_size $dist_path)
}
{
distribution: $dist_info
can_create_installers: true
supported_platforms: ["linux", "macos", "windows"]
installer_types: ["shell", "package", "gui"]
features: {
shell_installers: true
package_installers: false # Not fully implemented
gui_installers: false # Not fully implemented
uninstallers: true
service_management: true
}
}
}
# Quick installer creation with minimal options
def "main quick" [
distribution_path: string # Distribution to create installer for
--platform: string = "linux" # Single platform
--output-dir: string = "installers" # Output directory
] {
main $distribution_path --platforms $platform --installer-types shell --output-dir $output_dir
}