diff --git a/.gitignore b/.gitignore
index 712d01c..1b36d8f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@
/packages_temp.json
/APKINDEX
/APPINDEX
-/browser-amd64-nightly-linux.tar.gz
\ No newline at end of file
+/browser-amd64-nightly-linux.tar.gz
+/browser-amd64-nightly-windows.tar.gz
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a92ad4d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,145 @@
+
+
+
+
+
+ Spitfire Builder
+
+
+
+This is a "simple" script for building the Spitfire Browser based on Mozilla Firefox source code.
+
+
+## Dependencies
+
+- Mercurial (hg)
+- Git
+- Golang (tested with v1.21)
+- Python 3.11 and pip3
+
+# Example usage:
+
+## Build:
+
+```sh
+go run . -a
+```
+
+## Upload:
+
+```sh
+go run . --upload -c --upload-path=./mozilla-central/obj-x86_64-pc-linux-gnu/dist/bin
+```
+
+## Build and upload:
+
+```sh
+go run . --upload -c --upload-path=./mozilla-central/obj-x86_64-pc-linux-gnu/dist/bin -a
+```
+
+## Display all flags:
+
+```sh
+go run . -h
+```
+
+### Config file for uploading example:
+
+*sourceforge_config.json*
+
+```json
+{
+ "SFKeyPath": "~/.ssh/id_rsa.pub",
+ "SFUser": "internet-addict",
+ "SFHost": "web.sourceforge.net",
+ "SFProject": "spitfire-browser"
+}
+```
+
+## APPINDEX example:
+
+```
+C:905cd0cc2dea9e400e1ecd099462b6b19188a9f1
+P:Spitfire
+R:nightly
+V:2024.09.08
+A:amd64
+S:788506622
+I:3324483350
+T:Spitfire build
+U:https://spitfirebrowser.com/
+L:AGPL-3.0
+o:browser
+m:Internet Addict
+t:1725830641
+c:905cd0cc2dea9e400e1ecd099462b6b19188a9f1
+D:
+p:linux
+q:
+Z:905cd0cc2dea9e400e1ecd099462b6b19188a9f1
+```
+
+## Repositary structure
+
+```
+spitfire-browser/
+├── browser/
+│ ├── amd64/
+│ │ ├── stable/
+│ │ │ ├── latest/deb.tar.gz
+│ │ │ ├── x.x.x/deb.tar.gz
+│ │ ├── nightly/
+│ │ ├── latest/deb.tar.gz
+│ │ ├── yyyy-mm-dd/deb.tar.gz
+│ ├── arm/
+│ │ ├── stable/
+│ │ │ ├── latest/
+│ │ │ ├── x.x.x/
+│ │ ├── nightly/
+│ │ ├── latest/
+│ │ ├── yyyy-mm-dd/
+├── cli-package-manager/
+│ ├── stable/
+│ │ ├── latest/
+│ │ ├── x.x.x/
+│ ├── nightly/
+│ ├── latest/
+│ ├── yyyy-mm-dd/
+├── gui-installer/
+│ ├── stable/
+│ │ ├── latest/
+│ │ ├── x.x.x/
+│ ├── nightly/
+│ ├── latest/
+│ ├── yyyy-mm-dd/
+├── gui-package-manager/
+│ ├── stable/
+│ │ ├── latest/
+│ │ ├── x.x.x/
+│ ├── nightly/
+│ ├── latest/
+│ ├── yyyy-mm-dd/
+├── addons/
+│ ├── themes/
+│ │ ├── stable/
+│ │ │ ├── latest/
+│ │ │ ├── x.x.x/
+│ │ ├── nightly/
+│ │ ├── latest/
+│ │ ├── yyyy-mm-dd/
+│ ├── custom-configs/
+│ │ ├── stable/
+│ │ │ ├── latest/
+│ │ │ ├── x.x.x/
+│ │ ├── nightly/
+│ │ ├── latest/
+│ │ ├── yyyy-mm-dd/
+│ ├── search-engines/
+│ ├── stable/
+│ │ ├── latest/
+│ │ ├── x.x.x/
+│ ├── nightly/
+│ ├── latest/
+│ ├── yyyy-mm-dd/
+├── APPINDEX
+```
\ No newline at end of file
diff --git a/main.go b/main.go
index b829dbd..5eefa46 100644
--- a/main.go
+++ b/main.go
@@ -1,231 +1,254 @@
package main
import (
- "flag"
- "fmt"
- "log"
- "os"
- "path/filepath"
- "runtime" // for detecting system architecture and platform
- "time"
- "spitfire/spitfire"
- //"errors"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "runtime" // for detecting system architecture and platform
+ "spitfire/spitfire"
+ "time"
+ //"errors"
)
var (
- // Define all flags as package-level variables
- all bool
- buildFlag bool
- clean bool
- update bool
- patches bool
- run bool
- compress bool
- buildPath string
- target string
- version string
- component string
- arch string
- release string
- platform string
- upload bool
- uploadPath string
- sourceRepo = "https://hg.mozilla.org/mozilla-central"
- patchesRepo = "https://weforgecode.xyz/Spitfire/Browser.git"
- url = "https://spitfirebrowser.com/"
- licence = "AGPL-3.0"
- name = "Spitfire"
- maintainer = "Internet Addict"
- initialDir string
+ // Define all flags as package-level variables
+ all bool
+ buildFlag bool
+ clean bool
+ update bool
+ patches bool
+ run bool
+ compress bool
+ buildPath string
+ target string
+ version string
+ component string
+ arch string
+ release string
+ platform string
+ upload bool
+ uploadPath string
+ sourceRepo = "https://hg.mozilla.org/mozilla-central"
+ patchesRepo = "https://weforgecode.xyz/Spitfire/Browser.git"
+ url = "https://spitfirebrowser.com/"
+ licence = "AGPL-3.0"
+ name = "Spitfire"
+ maintainer = "Internet Addict"
+ initialDir string
)
func init() {
- flag.StringVar(&buildPath, "p", "", "Path to the build directory")
- 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, "Clean build")
- flag.BoolVar(&update, "u", false, "Update Mozilla repository")
- flag.BoolVar(&patches, "patches", false, "Update patches")
- 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.Bool("h", false, "Display help message")
+ flag.StringVar(&buildPath, "p", "", "Path to the build directory")
+ 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, "Clean build")
+ flag.BoolVar(&update, "u", false, "Update Mozilla repository")
+ flag.BoolVar(&patches, "patches", false, "Update patches")
+ 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.Bool("h", false, "Display help message")
}
func printHelp() {
- fmt.Println("Usage: ./main -p= -t= [-c|--compress] [-v|--version=] [-component=] [-arch=] [-release=] [-platform=]")
- flag.PrintDefaults()
- fmt.Println("Example: go run . --upload -c --upload-path=./mozilla-central/obj-x86_64-pc-linux-gnu/dist/bin -a")
- os.Exit(0)
+ fmt.Println("Usage: go run . -p= -t= [-c|--compress] [-v|--version=] [-component=] [-arch=] [-release=] [-platform=]")
+ flag.PrintDefaults()
+ fmt.Println("Example: go run . --upload -c --upload-path=./mozilla-central/obj-x86_64-pc-linux-gnu/dist/bin -a")
+ os.Exit(0)
}
func main() {
- flag.Parse()
+ // // Check system dependencies
+ // err := spitfire.CheckSystemDependencies()
+ // if err != nil {
+ // log.Fatalf("System check failed: %v", err)
+ // }
- if flag.Lookup("h").Value.(flag.Getter).Get().(bool) {
- printHelp()
- }
+ flag.Parse()
- // Set version to current date if it's empty and release is nightly
- if version == "" && release == "nightly" {
- version = time.Now().Format("2006.01.02") // Set version to current date if nightly
- }
+ if flag.Lookup("h").Value.(flag.Getter).Get().(bool) {
+ printHelp()
+ }
- // Save the initial directory
- var err error
- initialDir, err = os.Getwd()
- if err != nil {
- log.Fatalf("Failed to get current working directory: %v", err)
- }
- fmt.Printf("Initial working directory: %s\n", initialDir)
+ // Set version to current date if it's empty and release is nightly
+ if version == "" && release == "nightly" {
+ version = time.Now().Format("2006.01.02") // Set version to current date if nightly
+ }
- if all || buildFlag {
- BuildProcess()
- }
+ // Save the initial directory
+ var err2 error
+ initialDir, err2 = os.Getwd()
+ if err2 != nil {
+ log.Fatalf("Failed to get current working directory: %v", err2)
+ }
+ fmt.Printf("Initial working directory: %s\n", initialDir)
- if compress || upload {
- PackageAndUploadProcess()
- }
+ // Convert buildPath and uploadPath to absolute paths
+ if buildPath != "" {
+ buildPath, err2 = spitfire.ResolvePath(buildPath)
+ if err2 != nil {
+ log.Fatalf("Failed to convert buildPath to absolute path: %v", err2)
+ }
+ fmt.Printf("Resolved buildPath: %s\n", buildPath)
+ }
- spitfire.PrintErrors()
+ if uploadPath != "" {
+ uploadPath, err2 = spitfire.ResolvePath(uploadPath)
+ if err2 != nil {
+ log.Fatalf("Failed to convert uploadPath to absolute path: %v", err2)
+ }
+ fmt.Printf("Resolved uploadPath: %s\n", uploadPath)
+ }
+
+ if all || buildFlag {
+ BuildProcess()
+ }
+
+ if compress || upload {
+ PackageAndUploadProcess()
+ }
+
+ spitfire.PrintErrors()
}
// BuildProcess handles the build process: downloading, cleaning, configuring, and building the project.
func BuildProcess() {
- sourcePath, err := spitfire.ResolvePath("./mozilla-central")
- if err != nil {
- log.Fatalf("Error resolving source path: %v", err)
- }
+ sourcePath, err := spitfire.ResolvePath("./mozilla-central")
+ if err != nil {
+ log.Fatalf("Error resolving source path: %v", err)
+ }
- patchesDir, err := spitfire.ResolvePath(filepath.Join(sourcePath, "Spitfire"))
- if err != nil {
- log.Fatalf("Error resolving patches directory: %v", err)
- }
+ patchesDir, err := spitfire.ResolvePath(filepath.Join(sourcePath, "Spitfire"))
+ if err != nil {
+ log.Fatalf("Error resolving patches directory: %v", err)
+ }
- if all {
- spitfire.DownloadSource(sourcePath, sourceRepo)
- spitfire.DiscardChanges(sourcePath)
- spitfire.CleanBuild(sourcePath)
- spitfire.UpdateRepo(sourcePath)
- spitfire.UpdatePatches(patchesDir, patchesRepo, sourcePath)
- spitfire.Configure(sourcePath)
- spitfire.Build(sourcePath)
- if run {
- spitfire.RunProject(sourcePath)
- }
- fmt.Println("Spitfire build completed successfully.")
- } else if clean {
- spitfire.CleanBuild(sourcePath)
- fmt.Println("Cleaned Firefox build.")
- } else if update {
- spitfire.DownloadSource(sourcePath, sourceRepo)
- spitfire.UpdateRepo(sourcePath)
- fmt.Println("Mozilla repository updated.")
- } else if patches {
- spitfire.DownloadSource(sourcePath, sourceRepo)
- spitfire.UpdatePatches(patchesDir, patchesRepo, sourcePath)
- fmt.Println("Patches updated.")
- } else if buildFlag {
- spitfire.Configure(sourcePath)
- spitfire.Build(sourcePath)
- if run {
- spitfire.RunProject(sourcePath)
- }
- fmt.Println("Spitfire build completed successfully.")
- }
+ if all {
+ spitfire.DownloadSource(sourcePath, sourceRepo)
+ spitfire.DiscardChanges(sourcePath)
+ spitfire.CleanBuild(sourcePath)
+ spitfire.UpdateRepo(sourcePath)
+ spitfire.UpdatePatches(patchesDir, patchesRepo, sourcePath)
+ spitfire.Configure(sourcePath)
+ spitfire.Build(sourcePath)
+ if run {
+ spitfire.RunProject(sourcePath)
+ }
+ fmt.Println("Spitfire build completed successfully.")
+ } else if clean {
+ spitfire.CleanBuild(sourcePath)
+ fmt.Println("Cleaned Firefox build.")
+ } else if update {
+ spitfire.DownloadSource(sourcePath, sourceRepo)
+ spitfire.UpdateRepo(sourcePath)
+ fmt.Println("Mozilla repository updated.")
+ } else if patches {
+ spitfire.DownloadSource(sourcePath, sourceRepo)
+ spitfire.UpdatePatches(patchesDir, patchesRepo, sourcePath)
+ fmt.Println("Patches updated.")
+ } else if buildFlag {
+ spitfire.Configure(sourcePath)
+ spitfire.Build(sourcePath)
+ if run {
+ spitfire.RunProject(sourcePath)
+ }
+ fmt.Println("Spitfire build completed successfully.")
+ }
}
// PackageAndUploadProcess handles compressing, packaging, and uploading the build to SourceForge.
func PackageAndUploadProcess() {
-
- // Restore working directory before performing SourceForge operations
- restoreWorkingDirectory()
- pathToUse := buildPath
- if upload && uploadPath != "" {
- pathToUse = uploadPath
- }
+ // Restore working directory before performing SourceForge operations
+ restoreWorkingDirectory()
- if pathToUse == "" {
- log.Fatalf("Error: no valid build or upload path provided.")
- }
+ pathToUse := buildPath
+ if upload && uploadPath != "" {
+ pathToUse = uploadPath
+ }
- // // This is stupid, it wait for the path to exist (up to a maximum wait time)
- // err := waitForPath(pathToUse, 60, 5) // Max 60 seconds, checking every 5 seconds
- // if err != nil {
- // log.Fatalf("Error: Build path or upload path not found: %v", err)
- // }
+ if pathToUse == "" {
+ log.Fatalf("Error: no valid build or upload path provided.")
+ }
- uncompressedSize, err := spitfire.GetDirectorySize(pathToUse)
- if err != nil {
- log.Fatalf("Failed to calculate uncompressed size: %v", err)
- }
- fmt.Printf("Uncompressed directory size: %d bytes\n", uncompressedSize)
+ // // This is stupid, it wait for the path to exist (up to a maximum wait time)
+ // err := waitForPath(pathToUse, 60, 5) // Max 60 seconds, checking every 5 seconds
+ // if err != nil {
+ // log.Fatalf("Error: Build path or upload path not found: %v", err)
+ // }
- outputCompressedFile := filepath.Join(".", fmt.Sprintf("%s-%s-%s-%s.tar.gz", component, arch, release, platform))
- if compress {
- err := spitfire.CompressDirectory(pathToUse, outputCompressedFile)
- if err != nil {
- log.Fatalf("Failed to compress build directory: %v", err)
- }
- fmt.Printf("Build directory compressed to: %s\n", outputCompressedFile)
- }
+ uncompressedSize, err := spitfire.GetDirectorySize(pathToUse)
+ if err != nil {
+ log.Fatalf("Failed to calculate uncompressed size: %v", err)
+ }
+ fmt.Printf("Uncompressed directory size: %d bytes\n", uncompressedSize)
- compressedSize, err := spitfire.GetFileSize(outputCompressedFile)
- if err != nil {
- log.Fatalf("Failed to get compressed file size: %v", err)
- }
- fmt.Printf("Compressed file size: %d bytes\n", compressedSize)
+ outputCompressedFile := filepath.Join(".", fmt.Sprintf("%s-%s-%s-%s.tar.gz", component, arch, release, platform))
+ if compress {
+ err := spitfire.CompressDirectory(pathToUse, outputCompressedFile)
+ if err != nil {
+ log.Fatalf("Failed to compress build directory: %v", err)
+ }
+ fmt.Printf("Build directory compressed to: %s\n", outputCompressedFile)
+ }
- if upload {
- config, err := spitfire.LoadConfig()
- if err != nil {
- log.Fatalf("Failed to load SourceForge config: %v", err)
- }
+ compressedSize, err := spitfire.GetFileSize(outputCompressedFile)
+ if err != nil {
+ log.Fatalf("Failed to get compressed file size: %v", err)
+ }
+ fmt.Printf("Compressed file size: %d bytes\n", compressedSize)
- if _, err := os.Stat(outputCompressedFile); err == nil {
- err = spitfire.Upload(config, outputCompressedFile, "/home/frs/project/spitfire-browser/"+component+"/"+arch+"/"+release+"/"+version+"/")
- if err != nil {
- log.Fatalf("Failed to upload compressed file: %v", err)
- }
- fmt.Println("Compressed file uploaded successfully.")
- } else {
- log.Fatalf("No compressed file found to upload.")
- }
+ if upload {
+ config, err := spitfire.LoadConfig()
+ if err != nil {
+ log.Fatalf("Failed to load SourceForge config: %v", err)
+ }
- err = spitfire.DownloadAPPINDEX(config, "/home/frs/project/spitfire-browser/")
- if err != nil {
- fmt.Println("Failed to download APPINDEX. A new APPINDEX will be created and uploaded.")
- }
+ if _, err := os.Stat(outputCompressedFile); err == nil {
+ err = spitfire.Upload(config, outputCompressedFile, "/home/frs/project/spitfire-browser/"+component+"/"+arch+"/"+release+"/"+version+"/")
+ if err != nil {
+ log.Fatalf("Failed to upload compressed file: %v", err)
+ }
+ fmt.Println("Compressed file uploaded successfully.")
+ } else {
+ log.Fatalf("No compressed file found to upload.")
+ }
- err = spitfire.PackageAPPINDEX(
- name, release, version, arch,
- fmt.Sprintf("%d", compressedSize),
- fmt.Sprintf("%d", uncompressedSize),
- "Spitfire build", url, licence, component, maintainer, "", platform,
- )
- if err != nil {
- log.Fatalf("Failed to update APPINDEX: %v", err)
- }
- fmt.Println("APPINDEX updated successfully.")
+ err = spitfire.DownloadAPPINDEX(config, "/home/frs/project/spitfire-browser/")
+ if err != nil {
+ fmt.Println("Failed to download APPINDEX. A new APPINDEX will be created and uploaded.")
+ }
- if err := spitfire.CleanAppIndex(); err != nil {
- log.Fatalf("Failed to clean APPINDEX: %v", err)
- }
+ err = spitfire.PackageAPPINDEX(
+ name, release, version, arch,
+ fmt.Sprintf("%d", compressedSize),
+ fmt.Sprintf("%d", uncompressedSize),
+ "Spitfire build", url, licence, component, maintainer, "", platform,
+ )
+ if err != nil {
+ log.Fatalf("Failed to update APPINDEX: %v", err)
+ }
+ fmt.Println("APPINDEX updated successfully.")
- err = spitfire.UploadAPPINDEX(config, "/home/frs/project/spitfire-browser/")
- if err != nil {
- log.Fatalf("Failed to upload updated APPINDEX: %v", err)
- }
- fmt.Println("APPINDEX uploaded successfully.")
- }
+ if err := spitfire.CleanAppIndex(); err != nil {
+ log.Fatalf("Failed to clean APPINDEX: %v", err)
+ }
+
+ err = spitfire.UploadAPPINDEX(config, "/home/frs/project/spitfire-browser/")
+ if err != nil {
+ log.Fatalf("Failed to upload updated APPINDEX: %v", err)
+ }
+ fmt.Println("APPINDEX uploaded successfully.")
+ }
}
// // waitForPath checks if a path exists, waiting for up to maxWait seconds and retrying every interval seconds.
@@ -252,9 +275,9 @@ func PackageAndUploadProcess() {
// restoreWorkingDirectory restores the initial working directory after any operation that might change it.
func restoreWorkingDirectory() {
- err := os.Chdir(initialDir)
- if err != nil {
- log.Fatalf("Failed to restore the working directory: %v", err)
- }
- fmt.Printf("Restored working directory to: %s\n", initialDir)
-}
\ No newline at end of file
+ err := os.Chdir(initialDir)
+ if err != nil {
+ log.Fatalf("Failed to restore the working directory: %v", err)
+ }
+ fmt.Printf("Restored working directory to: %s\n", initialDir)
+}
diff --git a/sourceforge_config.json b/sourceforge_config.json
index c98a8cf..c1250c3 100644
--- a/sourceforge_config.json
+++ b/sourceforge_config.json
@@ -1,7 +1,6 @@
{
- "SFKeyPath": "~/.ssh/id_rsa.pub",
- "SFUser": "internet-addict",
- "SFHost": "web.sourceforge.net",
- "SFProject": "spitfire-browser"
- }
-
\ No newline at end of file
+ "SFKeyPath": "~/.ssh/id_rsa.pub",
+ "SFUser": "internet-addict",
+ "SFHost": "web.sourceforge.net",
+ "SFProject": "spitfire-browser"
+}
\ No newline at end of file
diff --git a/spitfire/build.go b/spitfire/build.go
index a35433a..3f5be5d 100644
--- a/spitfire/build.go
+++ b/spitfire/build.go
@@ -5,13 +5,39 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
)
// Array to store errors
var errors []string
+// SetGlobalEnv sets the MOZILLABUILD environment variable globally for the user (or system)
+func SetGlobalEnv(variable, value string, scope string) error {
+ if runtime.GOOS == "windows" {
+ var cmd *exec.Cmd
+ if scope == "user" {
+ cmd = exec.Command("setx", variable, value) // Set for current user
+ } else if scope == "system" {
+ cmd = exec.Command("setx", variable, value, "/M") // Set for system (requires admin privileges)
+ } else {
+ return fmt.Errorf("unknown scope: %s", scope)
+ }
+
+ // Run the command
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ return fmt.Errorf("failed to set environment variable %s=%s: %v\nOutput: %s", variable, value, err, string(out))
+ }
+ fmt.Printf("Successfully set %s=%s\n", variable, value)
+ return nil
+ } else {
+ return fmt.Errorf("global environment variable setting is not supported on non-Windows systems")
+ }
+}
+
// Run an external command like scp or rsync
func runCommand(command string, args ...string) error {
+ fmt.Printf("Running command: %s %v\n", command, args)
cmd := exec.Command(command, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@@ -20,9 +46,13 @@ func runCommand(command string, args ...string) error {
// 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", path)
+ return "", fmt.Errorf("failed to resolve path: %s, error: %v", path, err)
}
return absPath, nil
}
@@ -54,10 +84,21 @@ func CleanBuild(sourcePath string) {
errors = append(errors, "Failed to navigate to source directory.")
return
}
+
+ // Use the appropriate mach command for Windows or Unix-like systems
+ var machCmd string
+ if runtime.GOOS == "windows" {
+ machCmd = ".\\mach"
+ } else {
+ machCmd = "./mach"
+ }
+
+ // Revert uncommitted changes
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 {
+ // Clean the build
+ if err := runCommand(machCmd, "clobber"); err != nil {
errors = append(errors, "Failed to clean build.")
}
}
@@ -113,9 +154,19 @@ func UpdatePatches(patchesDir, patchesRepo, sourcePath string) {
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 err := runCommand("rsync", "-av", "--exclude=.git", patchesDir+"/", sourcePath+"/"); err != nil {
- errors = append(errors, "Failed to copy files.")
+ if runtime.GOOS == "windows" {
+ // Use robocopy for Windows
+ if err := runCommand("robocopy", patchesDir, sourcePath, "*", "/S", "/XF", ".git", "/XD", ".git"); 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).")
+ }
}
}
@@ -126,7 +177,16 @@ func Configure(sourcePath string) {
errors = append(errors, "Failed to navigate to source directory.")
return
}
- if err := runCommand("./mach", "configure"); err != nil {
+
+ // Use the appropriate mach command for Windows or Unix-like systems
+ var machCmd string
+ if runtime.GOOS == "windows" {
+ machCmd = ".\\mach"
+ } else {
+ machCmd = "./mach"
+ }
+
+ if err := runCommand(machCmd, "configure"); err != nil {
errors = append(errors, "Configuration failed.")
}
}
@@ -138,7 +198,16 @@ func Build(sourcePath string) {
errors = append(errors, "Failed to navigate to source directory.")
return
}
- if err := runCommand("./mach", "build"); err != nil {
+
+ // Use the appropriate mach command for Windows or Unix-like systems
+ var machCmd string
+ if runtime.GOOS == "windows" {
+ machCmd = ".\\mach"
+ } else {
+ machCmd = "./mach"
+ }
+
+ if err := runCommand(machCmd, "build"); err != nil {
errors = append(errors, "Build failed.")
}
}
@@ -146,11 +215,16 @@ func Build(sourcePath string) {
// 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
+
+ // Use the appropriate mach command for Windows or Unix-like systems
+ var machCmd string
+ if runtime.GOOS == "windows" {
+ machCmd = ".\\mach"
+ } else {
+ machCmd = "./mach"
}
- if err := runCommand("./mach", "run"); err != nil {
+
+ if err := runCommand(machCmd, "run"); err != nil {
errors = append(errors, "Failed to run the project.")
}
}
diff --git a/spitfire/checks.go b/spitfire/checks.go
new file mode 100644
index 0000000..c0bb232
--- /dev/null
+++ b/spitfire/checks.go
@@ -0,0 +1,78 @@
+package spitfire
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+)
+
+// CheckSystemDependencies ensures that required tools for building are installed.
+func CheckSystemDependencies() error {
+ requiredTools := map[string]string{
+ "git": "https://git-scm.com/download/win", // Git
+ "python": "https://www.python.org/downloads/", // Python
+ "pip3": "https://pip.pypa.io/en/stable/installing/", // Pip3
+ }
+
+ if runtime.GOOS == "windows" {
+ // Check for MozillaBuild installation
+ mozBuildPath := os.Getenv("MOZILLABUILD")
+ if mozBuildPath == "" {
+ mozBuildPath = "C:\\mozilla-build" // Default to standard MozillaBuild path
+ }
+
+ // Check if MozillaBuild exists at the specified location
+ if !dirExists(mozBuildPath) {
+ requiredTools["mozbuild"] = "https://ftp.mozilla.org/pub/mozilla/libraries/win32/MozillaBuildSetup-Latest.exe"
+ }
+ }
+
+ missingTools := []string{}
+
+ // Check for each required tool
+ for tool, downloadLink := range requiredTools {
+ if !isCommandAvailable(tool) {
+ missingTools = append(missingTools, fmt.Sprintf("%s (Download: %s)", tool, downloadLink))
+ }
+ }
+
+ // Special check for mach in the local source directory (mozilla-central)
+ machPath := filepath.Join("mozilla-central", "mach")
+ if !fileExists(machPath) {
+ missingTools = append(missingTools, fmt.Sprintf("mach (run from mozilla-central directory)"))
+ }
+
+ if len(missingTools) > 0 {
+ fmt.Println("The following tools are missing and are required for the build:")
+ for _, tool := range missingTools {
+ fmt.Println(" - " + tool)
+ }
+ return fmt.Errorf("missing required tools")
+ }
+
+ fmt.Println("All required system dependencies are installed.")
+ return nil
+}
+
+// isCommandAvailable checks if a command/tool is available on the system.
+func isCommandAvailable(command string) bool {
+ _, err := exec.LookPath(command)
+ return err == nil
+}
+
+// fileExists checks if a file exists at the given path.
+func fileExists(path string) bool {
+ _, err := os.Stat(path)
+ return err == nil
+}
+
+// dirExists checks if a directory exists at the given path.
+func dirExists(path string) bool {
+ info, err := os.Stat(path)
+ if os.IsNotExist(err) {
+ return false
+ }
+ return info.IsDir()
+}