- Add internal/phases/ with complete phase management system - Add internal/types/ with core data structures - Add internal/treefile/ for OSTree treefile generation - Update examples with YAML configurations - Update .gitignore to properly exclude test artifacts and build outputs - Update dependencies and configuration files
250 lines
7.2 KiB
Go
250 lines
7.2 KiB
Go
package phases
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"deb-bootc-compose/internal/types"
|
|
)
|
|
|
|
// BuildPhase handles package building using the build system
|
|
type BuildPhase struct {
|
|
PhaseBase
|
|
}
|
|
|
|
// NewBuildPhase creates a new BuildPhase
|
|
func NewBuildPhase() *BuildPhase {
|
|
return &BuildPhase{
|
|
PhaseBase: NewPhaseBase("build", []string{"gather"}),
|
|
}
|
|
}
|
|
|
|
// Run executes the build phase
|
|
func (p *BuildPhase) Run(engine types.Engine) error {
|
|
logger := engine.GetLogger()
|
|
logger.Printf("Starting build phase")
|
|
|
|
// Get build system
|
|
buildSystem := engine.GetBuildSystem()
|
|
if buildSystem == nil {
|
|
logger.Printf("No build system configured, skipping build phase")
|
|
return nil
|
|
}
|
|
|
|
// Test build system connection
|
|
if err := buildSystem.TestConnection(); err != nil {
|
|
return fmt.Errorf("build system connection failed: %w", err)
|
|
}
|
|
|
|
// Get treefile and process variants
|
|
treefile := engine.GetTreefile()
|
|
|
|
for _, variant := range treefile.Variants {
|
|
for _, arch := range variant.Architectures {
|
|
logger.Printf("Building variant %s for architecture %s", variant.Name, arch)
|
|
|
|
// Create build work directory
|
|
buildWorkDir := filepath.Join(engine.GetWorkDir(), "variants", variant.Name, arch, "build")
|
|
if err := os.MkdirAll(buildWorkDir, 0755); err != nil {
|
|
return fmt.Errorf("failed to create build work directory: %w", err)
|
|
}
|
|
|
|
// Build packages for this variant/architecture
|
|
if err := p.buildVariant(engine, buildWorkDir, variant, arch); err != nil {
|
|
return fmt.Errorf("failed to build variant %s for architecture %s: %w", variant.Name, arch, err)
|
|
}
|
|
|
|
logger.Printf("Completed building variant %s for architecture %s", variant.Name, arch)
|
|
}
|
|
}
|
|
|
|
logger.Printf("Build phase completed successfully")
|
|
return nil
|
|
}
|
|
|
|
// buildVariant builds packages for a specific variant and architecture
|
|
func (p *BuildPhase) buildVariant(engine types.Engine, workDir string, variant types.Variant, arch string) error {
|
|
logger := engine.GetLogger()
|
|
buildSystem := engine.GetBuildSystem()
|
|
|
|
// Get packages for this variant
|
|
packages := engine.GetTreefile().GetPackagesForVariant(variant.Name, arch)
|
|
|
|
// Create build environment
|
|
logger.Printf("Creating build environment for architecture %s", arch)
|
|
buildEnv, err := buildSystem.CreateBuildEnvironment(arch)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create build environment: %w", err)
|
|
}
|
|
|
|
// Ensure cleanup of build environment
|
|
defer func() {
|
|
if err := buildSystem.CleanupBuildEnvironment(buildEnv); err != nil {
|
|
logger.Printf("Warning: failed to cleanup build environment: %v", err)
|
|
}
|
|
}()
|
|
|
|
// Collect all packages to build
|
|
allPackages := make([]string, 0)
|
|
allPackages = append(allPackages, packages.Required...)
|
|
allPackages = append(allPackages, packages.Optional...)
|
|
allPackages = append(allPackages, packages.Recommended...)
|
|
allPackages = append(allPackages, packages.Development...)
|
|
allPackages = append(allPackages, packages.Kernel...)
|
|
allPackages = append(allPackages, packages.Bootloader...)
|
|
|
|
// Remove duplicates
|
|
uniquePackages := make(map[string]bool)
|
|
for _, pkg := range allPackages {
|
|
uniquePackages[pkg] = true
|
|
}
|
|
|
|
// Build each package
|
|
buildResults := make([]*types.BuildResult, 0)
|
|
for pkgName := range uniquePackages {
|
|
logger.Printf("Building package: %s", pkgName)
|
|
|
|
// Build the package
|
|
result, err := buildSystem.BuildPackage(pkgName, arch)
|
|
if err != nil {
|
|
logger.Printf("Warning: failed to build package %s: %v", pkgName, err)
|
|
continue
|
|
}
|
|
|
|
// Wait for build to complete
|
|
completedResult, err := buildSystem.WaitForBuild(result.ID, 30*time.Minute)
|
|
if err != nil {
|
|
logger.Printf("Warning: failed to wait for build of package %s: %v", pkgName, err)
|
|
continue
|
|
}
|
|
|
|
if completedResult == nil {
|
|
logger.Printf("Warning: build result is nil for package %s", pkgName)
|
|
continue
|
|
}
|
|
|
|
buildResults = append(buildResults, completedResult)
|
|
logger.Printf("Successfully built package: %s", pkgName)
|
|
}
|
|
|
|
// Write build results
|
|
if err := p.writeBuildResults(workDir, buildResults); err != nil {
|
|
return fmt.Errorf("failed to write build results: %w", err)
|
|
}
|
|
|
|
// Write build summary
|
|
if err := p.writeBuildSummary(workDir, buildResults, variant, arch); err != nil {
|
|
return fmt.Errorf("failed to write build summary: %w", err)
|
|
}
|
|
|
|
logger.Printf("Built %d packages for variant %s on architecture %s", len(buildResults), variant.Name, arch)
|
|
return nil
|
|
}
|
|
|
|
// writeBuildResults writes build results to files
|
|
func (p *BuildPhase) writeBuildResults(workDir string, results []*types.BuildResult) error {
|
|
// Create results directory
|
|
resultsDir := filepath.Join(workDir, "results")
|
|
if err := os.MkdirAll(resultsDir, 0755); err != nil {
|
|
return fmt.Errorf("failed to create results directory: %w", err)
|
|
}
|
|
|
|
// Write successful builds
|
|
successful := make([]string, 0)
|
|
failed := make([]string, 0)
|
|
|
|
for _, result := range results {
|
|
if result.Result == "success" {
|
|
successful = append(successful, result.PackageName)
|
|
} else {
|
|
failed = append(failed, result.PackageName)
|
|
}
|
|
}
|
|
|
|
// Write successful packages
|
|
if err := p.writePackageList(resultsDir, "successful", successful); err != nil {
|
|
return fmt.Errorf("failed to write successful packages: %w", err)
|
|
}
|
|
|
|
// Write failed packages
|
|
if err := p.writePackageList(resultsDir, "failed", failed); err != nil {
|
|
return fmt.Errorf("failed to write failed packages: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// writeBuildSummary writes a summary of the build process
|
|
func (p *BuildPhase) writeBuildSummary(workDir string, results []*types.BuildResult, variant types.Variant, arch string) error {
|
|
summaryFile := filepath.Join(workDir, "build-summary.txt")
|
|
|
|
summary := fmt.Sprintf(`Build Summary for Variant: %s
|
|
Architecture: %s
|
|
Timestamp: %s
|
|
|
|
Total Packages: %d
|
|
Successful Builds: %d
|
|
Failed Builds: %d
|
|
|
|
Successful Packages:
|
|
`, variant.Name, arch, time.Now().Format(time.RFC3339), len(results),
|
|
len(results), 0) // For now, assume all successful
|
|
|
|
// Count successful builds
|
|
successfulCount := 0
|
|
for _, result := range results {
|
|
if result.Result == "success" {
|
|
successfulCount++
|
|
summary += fmt.Sprintf(" - %s\n", result.PackageName)
|
|
}
|
|
}
|
|
|
|
summary += fmt.Sprintf("\nFailed Packages:\n")
|
|
failedCount := 0
|
|
for _, result := range results {
|
|
if result.Result != "success" {
|
|
failedCount++
|
|
summary += fmt.Sprintf(" - %s (%s)\n", result.PackageName, result.Result)
|
|
}
|
|
}
|
|
|
|
// Update counts
|
|
summary = fmt.Sprintf(`Build Summary for Variant: %s
|
|
Architecture: %s
|
|
Timestamp: %s
|
|
|
|
Total Packages: %d
|
|
Successful Builds: %d
|
|
Failed Builds: %d
|
|
|
|
Successful Packages:
|
|
`, variant.Name, arch, time.Now().Format(time.RFC3339), len(results),
|
|
successfulCount, failedCount) + summary
|
|
|
|
if err := os.WriteFile(summaryFile, []byte(summary), 0644); err != nil {
|
|
return fmt.Errorf("failed to write build summary: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// writePackageList writes a list of packages to a file
|
|
func (p *BuildPhase) writePackageList(dir, name string, packages []string) error {
|
|
if len(packages) == 0 {
|
|
return nil
|
|
}
|
|
|
|
filename := filepath.Join(dir, name+".txt")
|
|
content := ""
|
|
for _, pkg := range packages {
|
|
content += pkg + "\n"
|
|
}
|
|
|
|
if err := os.WriteFile(filename, []byte(content), 0644); err != nil {
|
|
return fmt.Errorf("failed to write package list %s: %w", name, err)
|
|
}
|
|
|
|
return nil
|
|
}
|