package spitfire import ( "fmt" "os" "os/exec" "path/filepath" "runtime" ) // Array to store errors var errors []string // Check and Set MOZILLABUILD environment variable automatically func setMozillaBuildEnv() error { // Check if MOZILLABUILD is already set if os.Getenv("MOZILLABUILD") != "" { fmt.Println("MOZILLABUILD environment variable is already set.") return nil } // Try to detect the MozillaBuild installation directory defaultPaths := []string{ "C:\\mozilla-build", "C:\\Program Files\\mozilla-build", "C:\\Program Files (x86)\\mozilla-build", } for _, path := range defaultPaths { if _, err := os.Stat(path); !os.IsNotExist(err) { // Set the MOZILLABUILD environment variable fmt.Printf("Setting MOZILLABUILD environment variable to: %s\n", path) return os.Setenv("MOZILLABUILD", path) } } // If no directory was found, return an error return fmt.Errorf("MozillaBuild directory not found. Please install MozillaBuild or set the MOZILLABUILD environment variable manually.") } // Run an external command like scp or rsync func runCommand(command string, args ...string) error { // Make sure the MOZILLABUILD environment variable is set for the mach commands if err := setMozillaBuildEnv(); err != nil { return err } cmd := exec.Command(command, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return cmd.Run() } // Function to resolve paths using absolute path func ResolvePath(path string) (string, error) { // Convert Unix-style slashes to the platform's native slashes path = filepath.FromSlash(path) // Get the absolute path absPath, err := filepath.Abs(path) if err != nil { return "", fmt.Errorf("failed to resolve path: %s, error: %v", path, err) } return absPath, nil } // Function to download Mozilla source if not present func DownloadSource(sourcePath string, sourceRepo string) { if _, err := os.Stat(sourcePath); os.IsNotExist(err) { fmt.Println("Mozilla source not found. Cloning from repository...") if err := runCommand("hg", "clone", sourceRepo, sourcePath); err != nil { errors = append(errors, "Failed to clone Mozilla repository.") } } else { fmt.Println("Mozilla source already exists.") } } // Function to discard uncommitted changes func DiscardChanges(sourcePath string) { fmt.Println("Discarding uncommitted changes...") if err := runCommand("hg", "revert", "--all", "--no-backup", "-R", sourcePath); err != nil { errors = append(errors, "Failed to revert changes in Mozilla repository.") } } // Function to clean build func CleanBuild(sourcePath string) { fmt.Println("Cleaning build...") if err := os.Chdir(sourcePath); err != nil { errors = append(errors, "Failed to navigate to source directory.") return } if err := runCommand("hg", "revert", "--all", "--no-backup"); err != nil { errors = append(errors, "Failed to revert changes in Mozilla repository.") } if err := runCommand("./mach", "clobber"); err != nil { errors = append(errors, "Failed to clean build.") } } // Function to update Mozilla repository func UpdateRepo(sourcePath string) { fmt.Println("Updating Mozilla repository...") if err := os.Chdir(sourcePath); err != nil { errors = append(errors, "Failed to navigate to source directory.") return } if err := runCommand("hg", "pull", "-u"); err != nil { errors = append(errors, "Failed to update Mozilla repository.") } } // Function to update patches func UpdatePatches(patchesDir, patchesRepo, sourcePath string) { fmt.Println("Updating patches...") if _, err := os.Stat(patchesDir); err == nil { fmt.Println("Patches directory already exists. Cleaning and pulling updates...") if err := os.Chdir(patchesDir); err != nil { errors = append(errors, "Failed to navigate to patches directory.") return } if err := runCommand("git", "clean", "-xdf"); err != nil { errors = append(errors, "Failed to clean patches directory.") } _ = runCommand("git", "stash", "push", "--include-untracked") if err := runCommand("git", "fetch"); err != nil { errors = append(errors, "Failed to fetch updates from patches repository.") } if runCommand("git", "show-ref", "--verify", "--quiet", "refs/heads/main") == nil { if err := runCommand("git", "rebase", "origin/main"); err != nil { errors = append(errors, "Failed to rebase updates from main branch.") } } else if runCommand("git", "show-ref", "--verify", "--quiet", "refs/heads/master") == nil { if err := runCommand("git", "rebase", "origin/master"); err != nil { errors = append(errors, "Failed to rebase updates from master branch.") } } else { errors = append(errors, "No valid branch (main or master) found in patches repository.") return } if runCommand("git", "stash", "list") == nil { _ = runCommand("git", "stash", "pop") } else { fmt.Println("No stash entries found, skipping pop.") } } else { fmt.Println("Patches directory does not exist. Cloning repository...") if err := runCommand("git", "clone", patchesRepo, patchesDir); err != nil { errors = append(errors, "Failed to clone patches repository.") } } // Handle platform-specific rsync command fmt.Println("Copying files from patches directory to Firefox source directory...") if runtime.GOOS == "windows" { // Use robocopy for Windows instead of rsync if err := runCommand("robocopy", patchesDir, sourcePath, "/MIR"); err != nil { errors = append(errors, "Failed to copy files (Windows robocopy).") } } else { // Use rsync for Unix-like systems if err := runCommand("rsync", "-av", "--exclude=.git", patchesDir+"/", sourcePath+"/"); err != nil { errors = append(errors, "Failed to copy files (rsync).") } } } // Function to configure Spitfire func Configure(sourcePath string) { fmt.Println("Configuring Spitfire...") if err := os.Chdir(sourcePath); err != nil { errors = append(errors, "Failed to navigate to source directory.") return } if err := runCommand("./mach", "configure"); err != nil { errors = append(errors, "Configuration failed.") } } // Function to build Spitfire func Build(sourcePath string) { fmt.Println("Building Spitfire...") if err := os.Chdir(sourcePath); err != nil { errors = append(errors, "Failed to navigate to source directory.") return } if err := runCommand("./mach", "build"); err != nil { errors = append(errors, "Build failed.") } } // Function to run the project after build func RunProject(sourcePath string) { fmt.Println("Running the project...") if err := os.Chdir(sourcePath); err != nil { errors = append(errors, "Failed to navigate to source directory.") return } if err := runCommand("./mach", "run"); err != nil { errors = append(errors, "Failed to run the project.") } } // Function to print collected errors func PrintErrors() { if len(errors) > 0 { fmt.Println("The following errors occurred during execution:") for _, err := range errors { fmt.Printf("- %s\n", err) } } }