1203 lines
36 KiB
Plaintext
1203 lines
36 KiB
Plaintext
#!/usr/bin/env nu
|
|
|
|
# Main distribution generator - orchestrates complete distribution creation
|
|
#
|
|
# Orchestrates:
|
|
# - Core library preparation
|
|
# - Platform service compilation
|
|
# - Configuration bundling
|
|
# - Documentation generation
|
|
# - Installation package creation
|
|
# - Multi-platform distribution assembly
|
|
|
|
use std log
|
|
|
|
def main [
|
|
--version: string = "" # Distribution version (auto-detected if empty)
|
|
--platforms: string = "linux,macos,windows" # Target platforms
|
|
--variants: string = "complete,minimal" # Distribution variants
|
|
--output-dir: string = "dist" # Output directory for distributions
|
|
--build-clean # Clean build before generation
|
|
--include-sources # Include source code in distribution
|
|
--compress # Compress final distributions
|
|
--generate-docs # Generate documentation
|
|
--parallel-builds # Build platforms in parallel
|
|
--validate-output # Validate generated distributions
|
|
--verbose # Enable verbose logging
|
|
]: nothing -> record {
|
|
|
|
let repo_root = ($env.PWD | path dirname | path dirname | path dirname)
|
|
|
|
# Detect version if not provided
|
|
let target_version = if $version == "" {
|
|
detect_project_version $repo_root
|
|
} else {
|
|
$version
|
|
}
|
|
|
|
let target_platforms = ($platforms | split row "," | each { str trim })
|
|
let target_variants = ($variants | split row "," | each { str trim })
|
|
|
|
let distribution_config = {
|
|
version: $target_version
|
|
platforms: $target_platforms
|
|
variants: $target_variants
|
|
output_dir: ($output_dir | path expand)
|
|
build_clean: $build_clean
|
|
include_sources: $include_sources
|
|
compress: $compress
|
|
generate_docs: $generate_docs
|
|
parallel_builds: $parallel_builds
|
|
validate_output: $validate_output
|
|
verbose: $verbose
|
|
repo_root: $repo_root
|
|
}
|
|
|
|
log info $"Starting distribution generation with config: ($distribution_config)"
|
|
|
|
# Ensure output directory exists
|
|
mkdir ($distribution_config.output_dir)
|
|
|
|
let generation_results = []
|
|
|
|
try {
|
|
# Phase 1: Preparation
|
|
let preparation_result = prepare_distribution_environment $distribution_config
|
|
|
|
let generation_results = ($generation_results | append { phase: "preparation", result: $preparation_result })
|
|
|
|
if $preparation_result.status != "success" {
|
|
log error $"Distribution preparation failed: ($preparation_result.reason)"
|
|
exit 1
|
|
}
|
|
|
|
# Phase 2: Core Distribution
|
|
let core_result = generate_core_distribution $distribution_config
|
|
|
|
let generation_results = ($generation_results | append { phase: "core", result: $core_result })
|
|
|
|
if $core_result.status != "success" {
|
|
log error $"Core distribution generation failed: ($core_result.reason)"
|
|
exit 1
|
|
}
|
|
|
|
# Phase 3: Platform Services
|
|
let platform_result = generate_platform_distributions $distribution_config
|
|
|
|
let generation_results = ($generation_results | append { phase: "platform", result: $platform_result })
|
|
|
|
if $platform_result.status != "success" {
|
|
log error $"Platform distribution generation failed: ($platform_result.reason)"
|
|
exit 1
|
|
}
|
|
|
|
# Phase 4: Documentation
|
|
let docs_result = if $distribution_config.generate_docs {
|
|
generate_distribution_docs $distribution_config
|
|
} else {
|
|
{ status: "skipped", reason: "documentation generation disabled" }
|
|
}
|
|
|
|
let generation_results = ($generation_results | append { phase: "documentation", result: $docs_result })
|
|
|
|
# Phase 5: Assembly
|
|
let assembly_result = assemble_complete_distributions $distribution_config $generation_results
|
|
|
|
let generation_results = ($generation_results | append { phase: "assembly", result: $assembly_result })
|
|
|
|
if $assembly_result.status != "success" {
|
|
log error $"Distribution assembly failed: ($assembly_result.reason)"
|
|
exit 1
|
|
}
|
|
|
|
# Phase 6: Validation
|
|
let validation_result = if $distribution_config.validate_output {
|
|
validate_distributions $distribution_config $assembly_result
|
|
} else {
|
|
{ status: "skipped", reason: "validation disabled" }
|
|
}
|
|
|
|
let generation_results = ($generation_results | append { phase: "validation", result: $validation_result })
|
|
|
|
let summary = {
|
|
version: $distribution_config.version
|
|
platforms: ($distribution_config.platforms | length)
|
|
variants: ($distribution_config.variants | length)
|
|
total_distributions: ($assembly_result.distributions | length)
|
|
successful_phases: ($generation_results | where {|r| $r.result.status == "success"} | length)
|
|
output_directory: $distribution_config.output_dir
|
|
total_size: ($assembly_result.total_size)
|
|
generation_config: $distribution_config
|
|
phases: $generation_results
|
|
}
|
|
|
|
log info $"Distribution generation completed successfully - ($summary.total_distributions) distributions created"
|
|
|
|
return $summary
|
|
|
|
} catch {|err|
|
|
log error $"Distribution generation failed: ($err.msg)"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# Detect project version from various sources
|
|
def detect_project_version [repo_root: string]: nothing -> string {
|
|
cd $repo_root
|
|
|
|
# Try git tags first
|
|
let git_version = try {
|
|
let tag = (git describe --tags --exact-match HEAD 2>/dev/null | str trim)
|
|
if $tag != "" {
|
|
return ($tag | str replace "^v" "")
|
|
}
|
|
let latest = (git describe --tags --abbrev=0 2>/dev/null | str trim)
|
|
if $latest != "" {
|
|
return ($latest | str replace "^v" "")
|
|
}
|
|
""
|
|
} catch {
|
|
""
|
|
}
|
|
|
|
if $git_version != "" {
|
|
return $git_version
|
|
}
|
|
|
|
# Try Cargo.toml
|
|
let cargo_version = try {
|
|
let cargo_files = (glob **/Cargo.toml --depth 2)
|
|
if ($cargo_files | length) > 0 {
|
|
let cargo_data = (open ($cargo_files | get 0))
|
|
return $cargo_data.package.version
|
|
}
|
|
""
|
|
} catch {
|
|
""
|
|
}
|
|
|
|
if $cargo_version != "" {
|
|
return $cargo_version
|
|
}
|
|
|
|
# Fallback to date-based version
|
|
return $"dev-(date now | format date '%Y%m%d')"
|
|
}
|
|
|
|
# Prepare distribution environment
|
|
def prepare_distribution_environment [distribution_config: record]: nothing -> record {
|
|
log info "Preparing distribution environment..."
|
|
|
|
let start_time = (date now)
|
|
|
|
try {
|
|
# Clean build if requested
|
|
if $distribution_config.build_clean {
|
|
log info "Cleaning build environment..."
|
|
let clean_result = (nu ($distribution_config.repo_root | path join "src" "tools" "build" "clean-build.nu") --scope all)
|
|
if $distribution_config.verbose {
|
|
log info $"Clean result: ($clean_result.total_size_cleaned) bytes cleaned"
|
|
}
|
|
}
|
|
|
|
# Create distribution directory structure
|
|
let dist_structure = [
|
|
"platform"
|
|
"core"
|
|
"config"
|
|
"kcl"
|
|
"extensions"
|
|
"templates"
|
|
"docs"
|
|
"tmp"
|
|
]
|
|
|
|
for dir in $dist_structure {
|
|
mkdir ($distribution_config.output_dir | path join $dir)
|
|
}
|
|
|
|
# Validate dependencies
|
|
let dependency_check = validate_distribution_dependencies $distribution_config
|
|
|
|
if $dependency_check.missing_dependencies > 0 {
|
|
return {
|
|
status: "failed"
|
|
reason: $"Missing dependencies: ($dependency_check.missing | str join ', ')"
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
|
|
{
|
|
status: "success"
|
|
environment_ready: true
|
|
directory_structure: $dist_structure
|
|
dependency_check: $dependency_check
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Validate distribution dependencies
|
|
def validate_distribution_dependencies [distribution_config: record]: nothing -> record {
|
|
let required_tools = [
|
|
{ name: "nu", command: "nu --version", description: "Nushell shell" }
|
|
{ name: "git", command: "git --version", description: "Git version control" }
|
|
{ name: "cargo", command: "cargo --version", description: "Rust package manager" }
|
|
{ name: "rustc", command: "rustc --version", description: "Rust compiler" }
|
|
]
|
|
|
|
let optional_tools = [
|
|
{ name: "kcl", command: "kcl version", description: "KCL configuration language" }
|
|
{ name: "docker", command: "docker --version", description: "Docker containerization" }
|
|
{ name: "tar", command: "tar --version", description: "Archive creation" }
|
|
{ name: "zip", command: "zip -v", description: "Zip compression" }
|
|
]
|
|
|
|
mut available = []
|
|
mut missing = []
|
|
|
|
# Check required tools
|
|
for tool in $required_tools {
|
|
let check_result = try {
|
|
run-external $tool.command err> /dev/null | complete
|
|
} catch {
|
|
{ exit_code: 1 }
|
|
}
|
|
|
|
if $check_result.exit_code == 0 {
|
|
$available = ($available | append $tool.name)
|
|
} else {
|
|
$missing = ($missing | append $tool.name)
|
|
}
|
|
}
|
|
|
|
# Check optional tools
|
|
for tool in $optional_tools {
|
|
let check_result = try {
|
|
run-external $tool.command err> /dev/null | complete
|
|
} catch {
|
|
{ exit_code: 1 }
|
|
}
|
|
|
|
if $check_result.exit_code == 0 {
|
|
$available = ($available | append $tool.name)
|
|
}
|
|
}
|
|
|
|
{
|
|
required_available: (($required_tools | get name) | where {|name| $name in $available} | length)
|
|
total_required: ($required_tools | length)
|
|
optional_available: (($optional_tools | get name) | where {|name| $name in $available} | length)
|
|
total_optional: ($optional_tools | length)
|
|
missing_dependencies: ($missing | length)
|
|
available: $available
|
|
missing: $missing
|
|
}
|
|
}
|
|
|
|
# Generate core distribution
|
|
def generate_core_distribution [distribution_config: record]: nothing -> record {
|
|
log info "Generating core distribution..."
|
|
|
|
let start_time = (date now)
|
|
|
|
try {
|
|
# Use the build system to bundle core components
|
|
let bundle_result = (nu ($distribution_config.repo_root | path join "src" "tools" "build" "bundle-core.nu")
|
|
--output-dir ($distribution_config.output_dir | path join "core")
|
|
--config-dir ($distribution_config.output_dir | path join "config")
|
|
--validate
|
|
--compress:$distribution_config.compress
|
|
--exclude-dev
|
|
--verbose:$distribution_config.verbose)
|
|
|
|
if $bundle_result.failed > 0 {
|
|
return {
|
|
status: "failed"
|
|
reason: $"Core bundling failed with ($bundle_result.failed) failures"
|
|
bundle_result: $bundle_result
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
|
|
# Validate KCL schemas
|
|
let kcl_result = (nu ($distribution_config.repo_root | path join "src" "tools" "build" "validate-kcl.nu")
|
|
--output-dir ($distribution_config.output_dir | path join "kcl")
|
|
--format-code
|
|
--verbose:$distribution_config.verbose)
|
|
|
|
{
|
|
status: "success"
|
|
core_bundle: $bundle_result
|
|
kcl_validation: $kcl_result
|
|
components_bundled: $bundle_result.successful
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Generate platform distributions
|
|
def generate_platform_distributions [distribution_config: record]: nothing -> record {
|
|
log info "Generating platform distributions..."
|
|
|
|
let start_time = (date now)
|
|
|
|
try {
|
|
# Compile platform components for each target platform
|
|
let platform_results = if $distribution_config.parallel_builds {
|
|
compile_platforms_parallel $distribution_config
|
|
} else {
|
|
compile_platforms_sequential $distribution_config
|
|
}
|
|
|
|
let successful_platforms = ($platform_results | where status == "success" | length)
|
|
let total_platforms = ($platform_results | length)
|
|
|
|
if $successful_platforms == 0 {
|
|
return {
|
|
status: "failed"
|
|
reason: "No platforms compiled successfully"
|
|
platform_results: $platform_results
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
|
|
{
|
|
status: (if $successful_platforms == $total_platforms { "success" } else { "partial" })
|
|
platforms_compiled: $successful_platforms
|
|
total_platforms: $total_platforms
|
|
platform_results: $platform_results
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Compile platforms in parallel
|
|
def compile_platforms_parallel [distribution_config: record]: nothing -> list {
|
|
# For simplicity, using sequential compilation for now
|
|
# In a real implementation, you might use background processes
|
|
compile_platforms_sequential $distribution_config
|
|
}
|
|
|
|
# Compile platforms sequentially
|
|
def compile_platforms_sequential [distribution_config: record]: nothing -> list {
|
|
$distribution_config.platforms | each {|platform|
|
|
compile_single_platform $platform $distribution_config
|
|
}
|
|
}
|
|
|
|
# Compile platform components for a single platform
|
|
def compile_single_platform [platform: string, distribution_config: record]: nothing -> record {
|
|
log info $"Compiling platform: ($platform)"
|
|
|
|
let start_time = (date now)
|
|
let target_triple = get_rust_target_triple $platform
|
|
|
|
try {
|
|
# Compile platform components
|
|
let compile_result = (nu ($distribution_config.repo_root | path join "src" "tools" "build" "compile-platform.nu")
|
|
--target $target_triple
|
|
--release
|
|
--output-dir ($distribution_config.output_dir | path join "platform")
|
|
--verbose:$distribution_config.verbose
|
|
--clean:$distribution_config.build_clean)
|
|
|
|
{
|
|
platform: $platform
|
|
target: $target_triple
|
|
status: (if $compile_result.failed > 0 { "failed" } else { "success" })
|
|
compiled_components: $compile_result.successful
|
|
total_components: $compile_result.total
|
|
compile_result: $compile_result
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
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]: nothing -> string {
|
|
match $platform {
|
|
"linux" => "x86_64-unknown-linux-gnu"
|
|
"macos" => "x86_64-apple-darwin"
|
|
"windows" => "x86_64-pc-windows-gnu"
|
|
_ => $platform # Assume it's already a target triple
|
|
}
|
|
}
|
|
|
|
# Generate distribution documentation
|
|
def generate_distribution_docs [distribution_config: record]: nothing -> record {
|
|
log info "Generating distribution documentation..."
|
|
|
|
let start_time = (date now)
|
|
|
|
try {
|
|
let docs_dir = ($distribution_config.output_dir | path join "docs")
|
|
mkdir $docs_dir
|
|
|
|
# Generate README
|
|
let readme_content = generate_distribution_readme $distribution_config
|
|
$readme_content | save ($docs_dir | path join "README.md")
|
|
|
|
# Generate installation guide
|
|
let install_guide = generate_installation_guide $distribution_config
|
|
$install_guide | save ($docs_dir | path join "INSTALLATION.md")
|
|
|
|
# Generate changelog
|
|
let changelog = generate_distribution_changelog $distribution_config
|
|
$changelog | save ($docs_dir | path join "CHANGELOG.md")
|
|
|
|
# Copy additional documentation
|
|
copy_project_documentation $distribution_config $docs_dir
|
|
|
|
{
|
|
status: "success"
|
|
docs_generated: ["README.md", "INSTALLATION.md", "CHANGELOG.md"]
|
|
docs_directory: $docs_dir
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Generate distribution README
|
|
def generate_distribution_readme [distribution_config: record]: nothing -> string {
|
|
$"# Provisioning System v($distribution_config.version)
|
|
|
|
Cloud-native infrastructure provisioning and management system.
|
|
|
|
## Distribution Contents
|
|
|
|
This distribution includes:
|
|
|
|
- **Platform Binaries**: Core system executables for ($distribution_config.platforms | str join ', ')
|
|
- **Core Libraries**: Nushell libraries and modules
|
|
- **Configuration**: Default configuration templates
|
|
- **KCL Schemas**: Infrastructure as Code definitions
|
|
- **Documentation**: Installation and usage guides
|
|
|
|
## Quick Start
|
|
|
|
### Linux/macOS
|
|
```bash
|
|
sudo ./install.sh
|
|
```
|
|
|
|
### Windows
|
|
```cmd
|
|
install.bat
|
|
```
|
|
|
|
### Manual Installation
|
|
1. Extract the distribution archive
|
|
2. Copy binaries to your system PATH
|
|
3. Copy libraries to standard locations
|
|
4. Configure system settings
|
|
|
|
## Getting Started
|
|
|
|
After installation:
|
|
```bash
|
|
provisioning help
|
|
provisioning version
|
|
provisioning env
|
|
```
|
|
|
|
## Documentation
|
|
|
|
- **Installation Guide**: See INSTALLATION.md
|
|
- **Changelog**: See CHANGELOG.md
|
|
- **Online Documentation**: https://github.com/your-org/provisioning
|
|
|
|
## Support
|
|
|
|
For support and issues:
|
|
- GitHub: https://github.com/your-org/provisioning/issues
|
|
- Documentation: https://docs.provisioning.example.com
|
|
|
|
## License
|
|
|
|
This software is licensed under the MIT License.
|
|
|
|
---
|
|
|
|
Generated on: (date now | format date '%Y-%m-%d %H:%M:%S')
|
|
Distribution Version: ($distribution_config.version)
|
|
"
|
|
}
|
|
|
|
# Generate installation guide
|
|
def generate_installation_guide [distribution_config: record]: nothing -> string {
|
|
$"# Installation Guide
|
|
|
|
This guide covers installation of the Provisioning System v($distribution_config.version).
|
|
|
|
## System Requirements
|
|
|
|
### Minimum Requirements
|
|
- Operating System: Linux, macOS, or Windows
|
|
- Memory: 1GB RAM
|
|
- Disk Space: 500MB free space
|
|
- Network: Internet connection for downloads
|
|
|
|
### Supported Platforms
|
|
- Linux (x86_64)
|
|
- macOS (Intel)
|
|
- Windows (x86_64)
|
|
|
|
## Installation Methods
|
|
|
|
### 1. Automated Installation (Recommended)
|
|
|
|
#### Linux/macOS
|
|
```bash
|
|
# Download and extract distribution
|
|
tar -xzf provisioning-($distribution_config.version)-linux-complete.tar.gz
|
|
cd provisioning-($distribution_config.version)-linux-complete
|
|
|
|
# Run installer
|
|
sudo ./install.sh
|
|
```
|
|
|
|
#### Windows
|
|
```cmd
|
|
REM Extract distribution
|
|
unzip provisioning-($distribution_config.version)-windows-complete.zip
|
|
cd provisioning-($distribution_config.version)-windows-complete
|
|
|
|
REM Run installer as Administrator
|
|
install.bat
|
|
```
|
|
|
|
### 2. Manual Installation
|
|
|
|
#### Step 1: Extract Distribution
|
|
Extract the distribution archive to a temporary location.
|
|
|
|
#### Step 2: Install Binaries
|
|
Copy the binaries from `platform/` to your system PATH:
|
|
|
|
**Linux/macOS:**
|
|
```bash
|
|
sudo cp platform/* /usr/local/bin/
|
|
sudo chmod +x /usr/local/bin/provisioning-*
|
|
```
|
|
|
|
**Windows:**
|
|
```cmd
|
|
copy platform\\*.exe \"C:\\Program Files\\Provisioning\\bin\\\"
|
|
```
|
|
|
|
#### Step 3: Install Libraries
|
|
Copy the core libraries:
|
|
|
|
**Linux/macOS:**
|
|
```bash
|
|
sudo mkdir -p /usr/local/lib/provisioning
|
|
sudo cp -r core/* /usr/local/lib/provisioning/
|
|
```
|
|
|
|
**Windows:**
|
|
```cmd
|
|
mkdir \"C:\\Program Files\\Provisioning\\lib\"
|
|
xcopy core\\* \"C:\\Program Files\\Provisioning\\lib\\\" /E /Y
|
|
```
|
|
|
|
#### Step 4: Install Configuration
|
|
Copy default configuration files:
|
|
|
|
**Linux/macOS:**
|
|
```bash
|
|
sudo mkdir -p /etc/provisioning
|
|
sudo cp config/* /etc/provisioning/
|
|
```
|
|
|
|
**Windows:**
|
|
```cmd
|
|
mkdir \"C:\\ProgramData\\Provisioning\"
|
|
xcopy config\\* \"C:\\ProgramData\\Provisioning\\\" /E /Y
|
|
```
|
|
|
|
## Verification
|
|
|
|
After installation, verify the system is working:
|
|
|
|
```bash
|
|
# Check version
|
|
provisioning version
|
|
|
|
# Check environment
|
|
provisioning env
|
|
|
|
# Test help system
|
|
provisioning help
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables
|
|
- `PROVISIONING_HOME`: Installation directory
|
|
- `PROVISIONING_CONFIG`: Configuration file path
|
|
- `PROVISIONING_ENV`: Environment (dev/test/prod)
|
|
|
|
### Configuration Files
|
|
- `config.defaults.toml`: System defaults
|
|
- `config.user.toml`: User-specific settings
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
1. **Command not found**: Ensure binaries are in your PATH
|
|
2. **Permission denied**: Check file permissions and user privileges
|
|
3. **Missing dependencies**: Install required system packages
|
|
|
|
### Getting Help
|
|
- Run `provisioning help` for command help
|
|
- Check logs in the system log directory
|
|
- Visit https://github.com/your-org/provisioning/issues
|
|
|
|
## Uninstallation
|
|
|
|
To remove the Provisioning System:
|
|
|
|
**Linux/macOS:**
|
|
```bash
|
|
# Remove binaries
|
|
sudo rm /usr/local/bin/provisioning-*
|
|
|
|
# Remove libraries
|
|
sudo rm -rf /usr/local/lib/provisioning
|
|
|
|
# Remove configuration
|
|
sudo rm -rf /etc/provisioning
|
|
```
|
|
|
|
**Windows:**
|
|
```cmd
|
|
REM Remove installation directory
|
|
rmdir /S \"C:\\Program Files\\Provisioning\"
|
|
rmdir /S \"C:\\ProgramData\\Provisioning\"
|
|
```
|
|
|
|
---
|
|
|
|
For more detailed information, visit the online documentation.
|
|
"
|
|
}
|
|
|
|
# Generate distribution changelog
|
|
def generate_distribution_changelog [distribution_config: record]: nothing -> string {
|
|
# This would normally generate a changelog from git history
|
|
$"# Changelog
|
|
|
|
## v($distribution_config.version) - (date now | format date '%Y-%m-%d')
|
|
|
|
### New Features
|
|
- Complete distribution system with multi-platform support
|
|
- Automated installation scripts for all platforms
|
|
- Comprehensive configuration management
|
|
|
|
### Improvements
|
|
- Enhanced build system with parallel compilation
|
|
- Better error handling and validation
|
|
- Improved documentation and examples
|
|
|
|
### Bug Fixes
|
|
- Fixed platform-specific compatibility issues
|
|
- Resolved configuration loading problems
|
|
- Corrected installation script permissions
|
|
|
|
---
|
|
|
|
For detailed commit history, see the project repository.
|
|
"
|
|
}
|
|
|
|
# Copy project documentation
|
|
def copy_project_documentation [distribution_config: record, docs_dir: string] {
|
|
let source_docs = [
|
|
($distribution_config.repo_root | path join "README.md")
|
|
($distribution_config.repo_root | path join "LICENSE")
|
|
($distribution_config.repo_root | path join "CONTRIBUTING.md")
|
|
]
|
|
|
|
for doc_file in $source_docs {
|
|
if ($doc_file | path exists) {
|
|
let target_file = ($docs_dir | path join ($doc_file | path basename))
|
|
cp $doc_file $target_file
|
|
}
|
|
}
|
|
}
|
|
|
|
# Assemble complete distributions
|
|
def assemble_complete_distributions [
|
|
distribution_config: record
|
|
generation_results: list
|
|
]: nothing -> record {
|
|
log info "Assembling complete distributions..."
|
|
|
|
let start_time = (date now)
|
|
|
|
try {
|
|
mut assembled_distributions = []
|
|
mut total_size = 0
|
|
|
|
# Create distributions for each platform-variant combination
|
|
for platform in $distribution_config.platforms {
|
|
for variant in $distribution_config.variants {
|
|
let dist_result = assemble_single_distribution $platform $variant $distribution_config
|
|
|
|
if $dist_result.status == "success" {
|
|
$assembled_distributions = ($assembled_distributions | append $dist_result)
|
|
$total_size = $total_size + $dist_result.size
|
|
}
|
|
}
|
|
}
|
|
|
|
# Create source distribution if requested
|
|
let source_dist = if $distribution_config.include_sources {
|
|
create_source_distribution $distribution_config
|
|
} else {
|
|
{ status: "skipped", reason: "source distribution not requested" }
|
|
}
|
|
|
|
{
|
|
status: "success"
|
|
distributions: $assembled_distributions
|
|
source_distribution: $source_dist
|
|
total_distributions: ($assembled_distributions | length)
|
|
total_size: $total_size
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Assemble single distribution
|
|
def assemble_single_distribution [
|
|
platform: string
|
|
variant: string
|
|
distribution_config: record
|
|
]: nothing -> record {
|
|
let dist_name = $"provisioning-($distribution_config.version)-($platform)-($variant)"
|
|
let dist_dir = ($distribution_config.output_dir | path join "tmp" $dist_name)
|
|
|
|
try {
|
|
# Create distribution directory
|
|
mkdir $dist_dir
|
|
|
|
# Copy components based on variant
|
|
match $variant {
|
|
"complete" => {
|
|
copy_complete_distribution $distribution_config $dist_dir $platform
|
|
}
|
|
"minimal" => {
|
|
copy_minimal_distribution $distribution_config $dist_dir $platform
|
|
}
|
|
_ => {
|
|
return {
|
|
platform: $platform
|
|
variant: $variant
|
|
status: "failed"
|
|
reason: $"unknown variant: ($variant)"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Create installation scripts
|
|
create_installation_scripts $dist_dir $platform $distribution_config
|
|
|
|
# Create archive if compression is enabled
|
|
let final_path = if $distribution_config.compress {
|
|
create_distribution_archive $dist_dir $distribution_config.output_dir
|
|
} else {
|
|
# Move directory to final location
|
|
let final_dir = ($distribution_config.output_dir | path join $dist_name)
|
|
mv $dist_dir $final_dir
|
|
$final_dir
|
|
}
|
|
|
|
let dist_size = get_directory_size $final_path
|
|
|
|
{
|
|
platform: $platform
|
|
variant: $variant
|
|
status: "success"
|
|
name: $dist_name
|
|
path: $final_path
|
|
size: $dist_size
|
|
compressed: $distribution_config.compress
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
platform: $platform
|
|
variant: $variant
|
|
status: "failed"
|
|
reason: $err.msg
|
|
}
|
|
}
|
|
}
|
|
|
|
# Copy complete distribution components
|
|
def copy_complete_distribution [distribution_config: record, dist_dir: string, platform: string] {
|
|
# Copy all components
|
|
let components = [
|
|
{ source: "platform", target: "platform", filter_platform: true }
|
|
{ source: "core", target: "core", filter_platform: false }
|
|
{ source: "config", target: "config", filter_platform: false }
|
|
{ source: "kcl", target: "kcl", filter_platform: false }
|
|
{ source: "docs", target: "docs", filter_platform: false }
|
|
]
|
|
|
|
for component in $components {
|
|
let source_path = ($distribution_config.output_dir | path join $component.source)
|
|
let target_path = ($dist_dir | path join $component.target)
|
|
|
|
if ($source_path | path exists) {
|
|
if $component.filter_platform and $component.source == "platform" {
|
|
copy_platform_binaries $source_path $target_path $platform
|
|
} else {
|
|
cp -r $source_path $target_path
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Copy minimal distribution components
|
|
def copy_minimal_distribution [distribution_config: record, dist_dir: string, platform: string] {
|
|
# Copy only essential components
|
|
let essential_components = [
|
|
{ source: "platform", target: "platform", filter_platform: true }
|
|
{ source: "core", target: "core", filter_platform: false }
|
|
{ source: "config", target: "config", filter_platform: false }
|
|
]
|
|
|
|
for component in $essential_components {
|
|
let source_path = ($distribution_config.output_dir | path join $component.source)
|
|
let target_path = ($dist_dir | path join $component.target)
|
|
|
|
if ($source_path | path exists) {
|
|
if $component.filter_platform and $component.source == "platform" {
|
|
copy_platform_binaries $source_path $target_path $platform
|
|
} else {
|
|
cp -r $source_path $target_path
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Copy platform-specific binaries
|
|
def copy_platform_binaries [source_path: string, target_path: string, platform: string] {
|
|
mkdir $target_path
|
|
|
|
let all_binaries = (ls $source_path | where type == file | get name)
|
|
let target_suffix = get_rust_target_triple $platform
|
|
|
|
for binary in $all_binaries {
|
|
let binary_name = ($binary | path basename)
|
|
|
|
# Check if binary matches the platform
|
|
if ($binary_name | str contains $target_suffix) or not ($binary_name =~ "(linux|darwin|windows|gnu|msvc)") {
|
|
let target_name = ($binary_name | str replace $"-($target_suffix)" "")
|
|
cp $binary ($target_path | path join $target_name)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Create installation scripts
|
|
def create_installation_scripts [dist_dir: string, platform: string, distribution_config: record] {
|
|
match $platform {
|
|
"linux" | "macos" => {
|
|
let install_script = create_unix_install_script $distribution_config
|
|
$install_script | save ($dist_dir | path join "install.sh")
|
|
chmod +x ($dist_dir | path join "install.sh")
|
|
}
|
|
"windows" => {
|
|
let install_script = create_windows_install_script $distribution_config
|
|
$install_script | save ($dist_dir | path join "install.bat")
|
|
}
|
|
_ => {
|
|
log warning $"No installation script for platform: ($platform)"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Create Unix install script
|
|
def create_unix_install_script [distribution_config: record]: nothing -> string {
|
|
$"#!/bin/bash
|
|
# Provisioning System Installation Script
|
|
# Version: ($distribution_config.version)
|
|
|
|
set -e
|
|
|
|
INSTALL_DIR=\"/usr/local\"
|
|
CONFIG_DIR=\"/etc/provisioning\"
|
|
LIB_DIR=\"$INSTALL_DIR/lib/provisioning\"
|
|
|
|
echo \"Installing Provisioning System ($distribution_config.version)...\"
|
|
|
|
# Check for root privileges
|
|
if [[ $EUID -ne 0 ]]; then
|
|
echo \"This script must be run as root (use sudo)\"
|
|
exit 1
|
|
fi
|
|
|
|
# Install binaries
|
|
echo \"Installing binaries...\"
|
|
mkdir -p \"$INSTALL_DIR/bin\"
|
|
cp platform/* \"$INSTALL_DIR/bin/\"
|
|
chmod +x \"$INSTALL_DIR/bin/\"*
|
|
|
|
# Install libraries
|
|
echo \"Installing libraries...\"
|
|
mkdir -p \"$LIB_DIR\"
|
|
cp -r core/* \"$LIB_DIR/\"
|
|
|
|
# Install configuration
|
|
echo \"Installing configuration...\"
|
|
mkdir -p \"$CONFIG_DIR\"
|
|
cp -r config/* \"$CONFIG_DIR/\"
|
|
|
|
echo \"Installation complete!\"
|
|
echo \"Run 'provisioning help' to get started.\"
|
|
"
|
|
}
|
|
|
|
# Create Windows install script
|
|
def create_windows_install_script [distribution_config: record]: nothing -> string {
|
|
$"@echo off
|
|
REM Provisioning System Installation Script
|
|
REM Version: ($distribution_config.version)
|
|
|
|
echo Installing Provisioning System ($distribution_config.version)...
|
|
|
|
REM Create directories
|
|
mkdir \"C:\\Program Files\\Provisioning\\bin\" 2>NUL
|
|
mkdir \"C:\\Program Files\\Provisioning\\lib\" 2>NUL
|
|
mkdir \"C:\\ProgramData\\Provisioning\" 2>NUL
|
|
|
|
REM Install binaries
|
|
echo Installing binaries...
|
|
xcopy platform\\* \"C:\\Program Files\\Provisioning\\bin\\\" /Y /Q
|
|
|
|
REM Install libraries
|
|
echo Installing libraries...
|
|
xcopy core\\* \"C:\\Program Files\\Provisioning\\lib\\\" /Y /Q /S
|
|
|
|
REM Install configuration
|
|
echo Installing configuration...
|
|
xcopy config\\* \"C:\\ProgramData\\Provisioning\\\" /Y /Q /S
|
|
|
|
echo Installation complete!
|
|
echo Add \"C:\\Program Files\\Provisioning\\bin\" to your PATH
|
|
echo Run 'provisioning-orchestrator --help' to get started.
|
|
pause
|
|
"
|
|
}
|
|
|
|
# Create distribution archive
|
|
def create_distribution_archive [dist_dir: string, output_dir: string]: nothing -> string {
|
|
let dist_name = ($dist_dir | path basename)
|
|
let archive_name = $"($dist_name).tar.gz"
|
|
let archive_path = ($output_dir | path join $archive_name)
|
|
let parent_dir = ($dist_dir | path dirname)
|
|
|
|
cd $parent_dir
|
|
tar -czf $archive_path $dist_name
|
|
|
|
# Clean up directory
|
|
rm -rf $dist_dir
|
|
|
|
return $archive_path
|
|
}
|
|
|
|
# Create source distribution
|
|
def create_source_distribution [distribution_config: record]: nothing -> record {
|
|
log info "Creating source distribution..."
|
|
|
|
try {
|
|
let source_name = $"provisioning-($distribution_config.version)-source"
|
|
let source_dir = ($distribution_config.output_dir | path join "tmp" $source_name)
|
|
|
|
# Create source distribution directory
|
|
mkdir $source_dir
|
|
|
|
# Copy source files (excluding build artifacts and temporary files)
|
|
let exclude_patterns = [
|
|
"target/"
|
|
"dist/"
|
|
"*.tmp"
|
|
".git/"
|
|
"node_modules/"
|
|
"*.log"
|
|
]
|
|
|
|
# This is a simplified copy - in practice, you'd use more sophisticated filtering
|
|
cp -r ($distribution_config.repo_root | path join "src") ($source_dir | path join "src")
|
|
cp ($distribution_config.repo_root | path join "README.md") ($source_dir | path join "README.md")
|
|
cp ($distribution_config.repo_root | path join "LICENSE") ($source_dir | path join "LICENSE")
|
|
|
|
# Create source archive
|
|
let archive_path = create_distribution_archive $source_dir $distribution_config.output_dir
|
|
|
|
{
|
|
status: "success"
|
|
name: $source_name
|
|
path: $archive_path
|
|
size: (get_directory_size $archive_path)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
}
|
|
}
|
|
}
|
|
|
|
# Validate distributions
|
|
def validate_distributions [
|
|
distribution_config: record
|
|
assembly_result: record
|
|
]: nothing -> record {
|
|
log info "Validating generated distributions..."
|
|
|
|
let start_time = (date now)
|
|
|
|
try {
|
|
let validation_results = $assembly_result.distributions | each {|dist|
|
|
validate_single_distribution $dist $distribution_config
|
|
}
|
|
|
|
let successful_validations = ($validation_results | where status == "success" | length)
|
|
let total_validations = ($validation_results | length)
|
|
|
|
{
|
|
status: (if $successful_validations == $total_validations { "success" } else { "partial" })
|
|
validated_distributions: $successful_validations
|
|
total_distributions: $total_validations
|
|
validation_results: $validation_results
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
status: "failed"
|
|
reason: $err.msg
|
|
duration: ((date now) - $start_time)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Validate single distribution
|
|
def validate_single_distribution [dist: record, distribution_config: record]: nothing -> record {
|
|
# Use the package validation tool
|
|
try {
|
|
let validation_result = (nu ($distribution_config.repo_root | path join "src" "tools" "package" "validate-package.nu")
|
|
$dist.path
|
|
--validation-type quick
|
|
--skip-execution
|
|
--output-format json
|
|
--cleanup)
|
|
|
|
{
|
|
distribution: $dist.name
|
|
status: (if $validation_result.overall_status == "passed" { "success" } else { "failed" })
|
|
validation_result: $validation_result
|
|
}
|
|
|
|
} catch {|err|
|
|
{
|
|
distribution: $dist.name
|
|
status: "failed"
|
|
reason: $err.msg
|
|
}
|
|
}
|
|
}
|
|
|
|
# Get directory size
|
|
def get_directory_size [path: string]: nothing -> int {
|
|
if not ($path | path exists) {
|
|
return 0
|
|
}
|
|
|
|
let total_size = try {
|
|
if ($path | path type) == "file" {
|
|
ls $path | get 0.size
|
|
} else {
|
|
find $path -type f | each {|file| ls $file | get 0.size } | math sum
|
|
}
|
|
} catch {
|
|
0
|
|
}
|
|
|
|
return ($total_size | if $in == null { 0 } else { $in })
|
|
}
|
|
|
|
# Show distribution status
|
|
def "main status" [] {
|
|
let repo_root = ($env.PWD | path dirname | path dirname | path dirname)
|
|
let version = (detect_project_version $repo_root)
|
|
|
|
let dependency_check = validate_distribution_dependencies { repo_root: $repo_root }
|
|
|
|
{
|
|
project_version: $version
|
|
repository: $repo_root
|
|
supported_platforms: ["linux", "macos", "windows"]
|
|
supported_variants: ["complete", "minimal"]
|
|
dependencies: $dependency_check
|
|
distribution_ready: ($dependency_check.missing_dependencies == 0)
|
|
}
|
|
}
|
|
|
|
# Quick distribution generation
|
|
def "main quick" [
|
|
--platform: string = "linux" # Single platform to build
|
|
--variant: string = "complete" # Distribution variant
|
|
] {
|
|
main --platforms $platform --variants $variant --parallel-builds:false
|
|
} |