428 lines
15 KiB
Go
428 lines
15 KiB
Go
package main
|
||
|
||
import (
|
||
"flag"
|
||
"fmt"
|
||
"log"
|
||
"os"
|
||
"path/filepath"
|
||
"runtime"
|
||
"spitfire-builder/spitfire"
|
||
"time"
|
||
//"errors"
|
||
)
|
||
|
||
var (
|
||
all bool
|
||
buildFlag bool
|
||
clean bool
|
||
fullClean bool
|
||
update bool
|
||
prePatch bool
|
||
postPatch bool
|
||
skipPatchUpdate bool
|
||
run bool
|
||
compress bool
|
||
target string
|
||
version string
|
||
component string
|
||
arch string
|
||
release string
|
||
platform string
|
||
upload bool
|
||
uploadPath string
|
||
sourceRepo = "https://hg.mozilla.org/releases/mozilla-release"
|
||
patchesRepo = "https://weforge.xyz/Spitfire/Patcher.git"
|
||
url = "https://spitfirebrowser.xyz/"
|
||
licence = "AGPL-3.0"
|
||
name = "Spitfire"
|
||
packageName = "spitfire-browser"
|
||
maintainer = "Internet Addict"
|
||
initialDir string
|
||
skipDeps bool
|
||
ignoreErrors bool
|
||
)
|
||
|
||
var errors []error // This is also in build.go. Great! This code is a mess.
|
||
|
||
func init() {
|
||
flag.StringVar(&target, "t", "", "🎯 Target location format: component-arch-release-platform")
|
||
flag.BoolVar(&compress, "c", false, "🗜️ Compress the build directory into a tar.gz file before uploading")
|
||
flag.StringVar(&version, "v", "", "🏷️ Specify version for the package. For nightly, use current date if not specified.")
|
||
flag.StringVar(&component, "component", "browser", "🌐 Component name (default: browser)")
|
||
flag.StringVar(&arch, "arch", runtime.GOARCH, "💻 Architecture (default: system architecture)")
|
||
flag.StringVar(&release, "release", "nightly", "🌙 Release type (default: nightly)")
|
||
flag.StringVar(&platform, "platform", runtime.GOOS, "🖥️ Platform (default: system platform)")
|
||
flag.BoolVar(&all, "a", false, "🔄 Perform all steps (build, clean, update)")
|
||
flag.BoolVar(&buildFlag, "b", false, "🔨 Build Spitfire")
|
||
flag.BoolVar(&clean, "clean", false, "🧹 Revert uncommitted changes without removing build artifacts")
|
||
flag.BoolVar(&fullClean, "full-clean", false, "🧼 Perform a full clean by removing all build artifacts (clobber)")
|
||
flag.BoolVar(&update, "u", false, "🔄 Update Mozilla repository")
|
||
flag.BoolVar(&prePatch, "pre-patch", false, "🔧 Apply pre-build patches")
|
||
flag.BoolVar(&postPatch, "post-patch", false, "🔧 Apply post-build patches")
|
||
flag.BoolVar(&skipPatchUpdate, "skip-patch-update", false, "⏭️ Skip updating the patches repository")
|
||
flag.BoolVar(&run, "r", false, "🚀 Run the project after build")
|
||
flag.BoolVar(&upload, "upload", false, "📤 Upload the compressed build file to SourceForge")
|
||
flag.StringVar(&uploadPath, "upload-path", "", "📂 Path to the file to upload if no build present")
|
||
flag.BoolVar(&skipDeps, "skip-deps", false, "⏭️ Skip checking for required system dependencies")
|
||
flag.BoolVar(&ignoreErrors, "ignore-errors", false, "⚠️ Processes all steps even if errors occur")
|
||
flag.Bool("h", false, "ℹ️ Display help message")
|
||
}
|
||
|
||
func printHelp() {
|
||
fmt.Println("📖 Spitfire Build System Help")
|
||
fmt.Println("Usage: go run . [options]")
|
||
fmt.Println("")
|
||
fmt.Println("🚀 Main Operations:")
|
||
fmt.Println("")
|
||
fmt.Println("🔧 Build Options:")
|
||
fmt.Println(" -a, -all Perform all steps (build, clean, update)")
|
||
fmt.Println(" -b, -build Build Spitfire")
|
||
fmt.Println(" -r, -run Run the project after build")
|
||
fmt.Println("")
|
||
fmt.Println("🧹 Clean Options:")
|
||
fmt.Println(" -clean Revert uncommitted changes")
|
||
fmt.Println(" -full-clean Remove all build artifacts (clobber)")
|
||
fmt.Println("")
|
||
fmt.Println("🔄 Update Options:")
|
||
fmt.Println(" -u, -update Update Mozilla repository")
|
||
fmt.Println(" -pre-patch Apply pre-build patches")
|
||
fmt.Println(" -post-patch Apply post-build patches")
|
||
fmt.Println(" -skip-patch-update Skip updating patches repository")
|
||
fmt.Println("")
|
||
fmt.Println("📦 Package Options:")
|
||
fmt.Println(" -c, -compress Compress build directory to tar.gz")
|
||
fmt.Println(" -upload Upload compressed file to SourceForge")
|
||
fmt.Println(" -upload-path Path to file for upload")
|
||
fmt.Println("")
|
||
fmt.Println("⚙️ Configuration Options:")
|
||
fmt.Println(" -t, -target Target format: component-arch-release-platform")
|
||
fmt.Println(" -v, -version Package version (default: date for nightly)")
|
||
fmt.Println(" -component Component name (default: browser)")
|
||
fmt.Println(" -arch Architecture (default: system arch)")
|
||
fmt.Println(" -release Release type (default: nightly)")
|
||
fmt.Println(" -platform Platform (default: system OS)")
|
||
fmt.Println("")
|
||
fmt.Println("🔍 Other Options:")
|
||
fmt.Println(" -skip-deps Skip system dependency checks")
|
||
fmt.Println(" -ignore-errors Continue despite errors")
|
||
fmt.Println(" -h, -help Show this help message")
|
||
fmt.Println("")
|
||
fmt.Println("💡 Examples:")
|
||
fmt.Println(" Full build and upload: go run . -a -c -upload")
|
||
fmt.Println(" Just build: go run . -b")
|
||
fmt.Println(" Clean build: go run . -clean")
|
||
fmt.Println(" Upload existing: go run . -upload -upload-path=./build.tar.gz")
|
||
fmt.Println("")
|
||
fmt.Println("🌐 Project: https://weforge.xyz/Spitfire")
|
||
os.Exit(0)
|
||
}
|
||
|
||
func handleError(err error) {
|
||
if err != nil {
|
||
errors = append(errors, err)
|
||
if !ignoreErrors {
|
||
log.Fatal(err)
|
||
}
|
||
}
|
||
}
|
||
|
||
func main() {
|
||
flag.Parse()
|
||
|
||
if flag.Lookup("h").Value.(flag.Getter).Get().(bool) {
|
||
printHelp()
|
||
}
|
||
|
||
fmt.Println("🚀 Starting Spitfire build process...")
|
||
|
||
if !skipDeps {
|
||
fmt.Println("🔍 Checking system dependencies...")
|
||
if err := spitfire.CheckDependencies(); err != nil {
|
||
handleError(fmt.Errorf("❌ system check failed: %w", err))
|
||
}
|
||
fmt.Println("✅ All dependencies verified")
|
||
}
|
||
|
||
if version == "" && release == "nightly" {
|
||
version = time.Now().Format("2006.01.02")
|
||
fmt.Printf("📅 Using nightly version: %s\n", version)
|
||
}
|
||
|
||
// Save the initial directory
|
||
var err error
|
||
initialDir, err = os.Getwd()
|
||
if err != nil {
|
||
handleError(fmt.Errorf("❌ failed to get current directory: %w", err))
|
||
}
|
||
|
||
var buildDir string
|
||
|
||
if all || buildFlag || prePatch || postPatch || clean || update || run {
|
||
fmt.Println("🏗️ Starting build process...")
|
||
buildDir, err = BuildProcess()
|
||
if err != nil {
|
||
handleError(fmt.Errorf("❌ build process failed: %w", err))
|
||
} else if buildDir == "" && (buildFlag || all || run) {
|
||
handleError(fmt.Errorf("❌ build directory not found after build process"))
|
||
}
|
||
}
|
||
|
||
if compress || upload {
|
||
fmt.Println("📦 Packaging and uploading build...")
|
||
if err := PackageAndUploadProcess(buildDir); err != nil {
|
||
handleError(fmt.Errorf("❌ package/upload failed: %w", err))
|
||
}
|
||
}
|
||
|
||
spitfire.PrintErrors()
|
||
|
||
if len(errors) > 0 {
|
||
fmt.Fprintf(os.Stderr, "❌ Exiting with %d error(s):\n", len(errors))
|
||
for _, e := range errors {
|
||
fmt.Fprintf(os.Stderr, " - %v\n", e)
|
||
}
|
||
os.Exit(1)
|
||
} else {
|
||
fmt.Println("🎉 All operations completed successfully!")
|
||
os.Exit(0)
|
||
}
|
||
}
|
||
|
||
func BuildProcess() (string, error) {
|
||
fmt.Println("📂 Resolving source path...")
|
||
sourcePath, err := spitfire.ResolvePath("./mozilla-release")
|
||
if err != nil {
|
||
return "", fmt.Errorf("❌ resolve source path: %w", err)
|
||
}
|
||
|
||
var buildDir string
|
||
|
||
if all {
|
||
fmt.Println("🔄 Running full build process...")
|
||
if err := spitfire.DownloadSource(sourcePath, sourceRepo); err != nil {
|
||
return "", fmt.Errorf("❌ download source: %w", err)
|
||
}
|
||
if err := spitfire.DiscardChanges(sourcePath); err != nil {
|
||
return "", fmt.Errorf("❌ discard changes: %w", err)
|
||
}
|
||
if err := spitfire.CleanBuild(sourcePath, fullClean); err != nil {
|
||
return "", fmt.Errorf("❌ clean build: %w", err)
|
||
}
|
||
if err := spitfire.UpdateRepo(sourcePath); err != nil {
|
||
return "", fmt.Errorf("❌ update repo: %w", err)
|
||
}
|
||
if err := spitfire.ApplyPatches(sourcePath, patchesRepo, "pre-compile-patches", filepath.Join(sourcePath, "patcher"), skipPatchUpdate); err != nil {
|
||
return "", fmt.Errorf("❌ pre-patch: %w", err)
|
||
}
|
||
if err := spitfire.Configure(sourcePath); err != nil {
|
||
return "", fmt.Errorf("❌ configure: %w", err)
|
||
}
|
||
if err := spitfire.Build(sourcePath); err != nil {
|
||
return "", fmt.Errorf("❌ build: %w", err)
|
||
}
|
||
buildDir, err = spitfire.ResolveBuildDir(sourcePath)
|
||
if err != nil {
|
||
return "", fmt.Errorf("❌ resolve build dir: %w", err)
|
||
}
|
||
if err := spitfire.ApplyPatches(buildDir, patchesRepo, "post-compile-patches", filepath.Join(sourcePath, "patcher"), skipPatchUpdate); err != nil {
|
||
return "", fmt.Errorf("❌ post-patch: %w", err)
|
||
}
|
||
if run {
|
||
if err := spitfire.RunProject(sourcePath); err != nil {
|
||
return "", fmt.Errorf("❌ run project: %w", err)
|
||
}
|
||
}
|
||
fmt.Println("✅ Spitfire build completed successfully")
|
||
} else if buildFlag {
|
||
fmt.Println("🔨 Running build process...")
|
||
if prePatch {
|
||
if err := spitfire.ApplyPatches(sourcePath, patchesRepo, "pre-compile-patches", filepath.Join(sourcePath, "patcher"), skipPatchUpdate); err != nil {
|
||
return "", fmt.Errorf("❌ pre-patch: %w", err)
|
||
}
|
||
}
|
||
if err := spitfire.Configure(sourcePath); err != nil {
|
||
return "", fmt.Errorf("❌ configure: %w", err)
|
||
}
|
||
if err := spitfire.Build(sourcePath); err != nil {
|
||
return "", fmt.Errorf("❌ build: %w", err)
|
||
}
|
||
buildDir, err = spitfire.ResolveBuildDir(sourcePath)
|
||
if err != nil {
|
||
return "", fmt.Errorf("❌ resolve build dir: %w", err)
|
||
}
|
||
if postPatch {
|
||
if err := spitfire.ApplyPatches(buildDir, patchesRepo, "post-compile-patches", filepath.Join(sourcePath, "patcher"), skipPatchUpdate); err != nil {
|
||
return "", fmt.Errorf("❌ post-patch: %w", err)
|
||
}
|
||
}
|
||
if run {
|
||
if err := spitfire.RunProject(sourcePath); err != nil {
|
||
return "", fmt.Errorf("❌ run project: %w", err)
|
||
}
|
||
}
|
||
fmt.Println("✅ Spitfire build completed successfully")
|
||
} else if clean {
|
||
fmt.Println("🧹 Cleaning build...")
|
||
if err := spitfire.CleanBuild(sourcePath, fullClean); err != nil {
|
||
return "", fmt.Errorf("❌ clean build: %w", err)
|
||
}
|
||
fmt.Println("✅ Firefox build cleaned")
|
||
} else if update {
|
||
fmt.Println("🔄 Updating repository...")
|
||
if err := spitfire.DownloadSource(sourcePath, sourceRepo); err != nil {
|
||
return "", fmt.Errorf("❌ download source: %w", err)
|
||
}
|
||
if err := spitfire.UpdateRepo(sourcePath); err != nil {
|
||
return "", fmt.Errorf("❌ update repo: %w", err)
|
||
}
|
||
fmt.Println("✅ Mozilla repository updated")
|
||
} else if prePatch {
|
||
fmt.Println("🔧 Applying pre-compile patches...")
|
||
if err := spitfire.DownloadSource(sourcePath, sourceRepo); err != nil {
|
||
return "", fmt.Errorf("❌ download source: %w", err)
|
||
}
|
||
if err := spitfire.ApplyPatches(sourcePath, patchesRepo, "pre-compile-patches", filepath.Join(sourcePath, "patcher"), skipPatchUpdate); err != nil {
|
||
return "", fmt.Errorf("❌ pre-patch: %w", err)
|
||
}
|
||
fmt.Println("✅ Pre-compile patches applied")
|
||
} else if postPatch {
|
||
fmt.Println("🔧 Applying post-compile patches...")
|
||
buildDir, err = spitfire.ResolveBuildDir(sourcePath)
|
||
if err != nil {
|
||
return "", fmt.Errorf("❌ resolve build dir: %w", err)
|
||
}
|
||
if _, err := os.Stat(buildDir); err == nil {
|
||
if err := spitfire.ApplyPatches(buildDir, patchesRepo, "post-compile-patches", filepath.Join(sourcePath, "patcher"), skipPatchUpdate); err != nil {
|
||
return "", fmt.Errorf("❌ post-patch: %w", err)
|
||
}
|
||
}
|
||
if run {
|
||
if err := spitfire.RunProject(sourcePath); err != nil {
|
||
return "", fmt.Errorf("❌ run project: %w", err)
|
||
}
|
||
}
|
||
} else if run {
|
||
fmt.Println("🚀 Running project...")
|
||
if err := spitfire.RunProject(sourcePath); err != nil {
|
||
return "", fmt.Errorf("❌ run project: %w", err)
|
||
}
|
||
}
|
||
|
||
return buildDir, nil
|
||
}
|
||
|
||
func PackageAndUploadProcess(buildDir string) error {
|
||
fmt.Println("📦 Starting package and upload process...")
|
||
restoreWorkingDirectory()
|
||
|
||
pathToUse := buildDir
|
||
if upload && uploadPath != "" {
|
||
pathToUse = uploadPath
|
||
fmt.Printf(" ├─ Using custom upload path: %s\n", pathToUse)
|
||
}
|
||
|
||
if pathToUse == "" {
|
||
return fmt.Errorf("❌ no valid build or upload path provided")
|
||
}
|
||
|
||
fmt.Println("📏 Calculating directory size...")
|
||
uncompressedSize, err := spitfire.GetDirectorySize(pathToUse)
|
||
if err != nil {
|
||
return fmt.Errorf("❌ get directory size: %w", err)
|
||
}
|
||
fmt.Printf(" ├─ Uncompressed size: %s\n", spitfire.BytesToHumanReadable(uncompressedSize))
|
||
|
||
outputCompressedFile := filepath.Join(".", fmt.Sprintf(
|
||
"%s-%s-%s-%s.tar.gz",
|
||
component, arch, release, platform,
|
||
))
|
||
fmt.Printf(" ├─ Output filename: %s\n", outputCompressedFile)
|
||
|
||
if compress {
|
||
fmt.Println("🗜️ Compressing directory...")
|
||
if err := spitfire.CompressDirectory(pathToUse, outputCompressedFile); err != nil {
|
||
return fmt.Errorf("❌ compress directory: %w", err)
|
||
}
|
||
fmt.Printf("✅ Build directory compressed to: %s\n", outputCompressedFile)
|
||
}
|
||
|
||
compressedSize, err := spitfire.GetFileSize(outputCompressedFile)
|
||
if err != nil {
|
||
return fmt.Errorf("❌ get compressed file size: %w", err)
|
||
}
|
||
fmt.Printf(" ├─ Compressed size: %s\n", spitfire.BytesToHumanReadable(compressedSize))
|
||
|
||
compressionRatio, efficiency := spitfire.CalculateCompressionEfficiency(uncompressedSize, compressedSize)
|
||
fmt.Printf(" ├─ Compression ratio: %.2f:1\n", compressionRatio)
|
||
fmt.Printf(" ├─ Compression efficiency: %.2f%%\n", efficiency)
|
||
fmt.Printf(" └─ Source directory: %s\n", pathToUse)
|
||
|
||
if !upload {
|
||
fmt.Println("⏩ Upload skipped (not requested)")
|
||
return nil
|
||
}
|
||
|
||
fmt.Println("🔑 Loading configuration...")
|
||
config, err := spitfire.LoadConfig()
|
||
if err != nil {
|
||
return fmt.Errorf("❌ load config: %w", err)
|
||
}
|
||
|
||
if _, err := os.Stat(outputCompressedFile); err != nil {
|
||
return fmt.Errorf("❌ compressed file not found: %w", err)
|
||
}
|
||
|
||
uploadDir := fmt.Sprintf("%s/%s/%s/%s", component, arch, release, version)
|
||
fmt.Printf("📤 Uploading to: %s\n", uploadDir)
|
||
if err := spitfire.Upload(config, outputCompressedFile, "/home/frs/project/spitfire-browser/"+uploadDir+"/"); err != nil {
|
||
return fmt.Errorf("❌ upload compressed file: %w", err)
|
||
}
|
||
fmt.Println("✅ Compressed file uploaded successfully")
|
||
|
||
fmt.Println("📥 Downloading APPINDEX...")
|
||
if err := spitfire.DownloadAPPINDEX(config, "/home/frs/project/spitfire-browser/"); err != nil {
|
||
fmt.Println("⚠️ Failed to download APPINDEX - creating new one")
|
||
}
|
||
|
||
fmt.Println("📝 Updating APPINDEX...")
|
||
if err := spitfire.PackageAPPINDEX(
|
||
packageName,
|
||
release,
|
||
version,
|
||
arch,
|
||
fmt.Sprintf("%d", compressedSize),
|
||
fmt.Sprintf("%d", uncompressedSize),
|
||
name,
|
||
url,
|
||
licence,
|
||
component,
|
||
maintainer,
|
||
"",
|
||
platform,
|
||
uploadDir,
|
||
); err != nil {
|
||
return fmt.Errorf("❌ package APPINDEX: %w", err)
|
||
}
|
||
fmt.Println("✅ APPINDEX updated successfully")
|
||
|
||
fmt.Println("🧹 Cleaning APPINDEX...")
|
||
if err := spitfire.CleanAppIndex(); err != nil {
|
||
return fmt.Errorf("❌ clean APPINDEX: %w", err)
|
||
}
|
||
|
||
fmt.Println("📤 Uploading APPINDEX...")
|
||
if err := spitfire.UploadAPPINDEX(config, "/home/frs/project/spitfire-browser/"); err != nil {
|
||
return fmt.Errorf("❌ upload APPINDEX: %w", err)
|
||
}
|
||
fmt.Println("✅ APPINDEX uploaded successfully")
|
||
|
||
return nil
|
||
}
|
||
|
||
func restoreWorkingDirectory() {
|
||
fmt.Println("↩️ Restoring working directory...")
|
||
if err := os.Chdir(initialDir); err != nil {
|
||
log.Printf("⚠️ Failed to restore working directory: %v", err)
|
||
}
|
||
}
|