Builder/main.go

357 lines
11 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("Usage: go run . -p=<path-to-build> -t=<target> [-c|--compress] [-v|--version=<version>] [-component=<component>] [-arch=<architecture>] [-release=<release>] [-platform=<platform>]")
flag.PrintDefaults()
fmt.Println("Example: go run . --upload -c -a")
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()
}
if !skipDeps {
if err := spitfire.CheckDependencies(); err != nil {
handleError(fmt.Errorf("system check failed: %w", err))
}
}
if version == "" && release == "nightly" {
version = time.Now().Format("2006.01.02")
}
// 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 {
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 {
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 {
os.Exit(0)
}
}
func BuildProcess() (string, error) {
sourcePath, err := spitfire.ResolvePath("./mozilla-release")
if err != nil {
return "", fmt.Errorf("resolve source path: %w", err)
}
var buildDir string
if all {
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 {
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 {
if err := spitfire.CleanBuild(sourcePath, fullClean); err != nil {
return "", fmt.Errorf("clean build: %w", err)
}
fmt.Println("Cleaned Firefox build.")
} else if update {
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 {
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("Patches updated.")
} else if postPatch {
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 {
if err := spitfire.RunProject(sourcePath); err != nil {
return "", fmt.Errorf("run project: %w", err)
}
}
return buildDir, nil
}
func PackageAndUploadProcess(buildDir string) error {
restoreWorkingDirectory()
pathToUse := buildDir
if upload && uploadPath != "" {
pathToUse = uploadPath
}
if pathToUse == "" {
return fmt.Errorf("no valid build or upload path provided")
}
uncompressedSize, err := spitfire.GetDirectorySize(pathToUse)
if err != nil {
return fmt.Errorf("get directory size: %w", err)
}
fmt.Printf("Uncompressed directory size: %s\n", spitfire.BytesToHumanReadable(uncompressedSize))
outputCompressedFile := filepath.Join(".", fmt.Sprintf(
"%s-%s-%s-%s.tar.gz",
component, arch, release, platform,
))
if compress {
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 file 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("Compressed dir: %s\n", pathToUse)
if !upload {
return nil
}
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)
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.")
if err := spitfire.DownloadAPPINDEX(config, "/home/frs/project/spitfire-browser/"); err != nil {
fmt.Println("Failed to download APPINDEX. A new one will be created and uploaded.")
}
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.")
if err := spitfire.CleanAppIndex(); err != nil {
return fmt.Errorf("clean APPINDEX: %w", err)
}
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() {
if err := os.Chdir(initialDir); err != nil {
log.Printf("Failed to restore working directory: %v", err)
}
}