diff --git a/README.md b/README.md
deleted file mode 100644
index 63f036c..0000000
--- a/README.md
+++ /dev/null
@@ -1,88 +0,0 @@
-
-
-
-
-
- Spitfire Package Manager (SPM)
-
-
-
-A package management library designed to handle automatic updates for Spitfire browser and all of its components.
-
-
-### SPM is currently used in:
-- [Spitfire Luncher](https://weforge.xyz/Spitfire/Luncher)
-- [Spitfire Insaller](https://weforge.xyz/Spitfire/Installer)
-
-### Example usage:
-
-To use SPM for downloading, decompressing, and installing updates, implement the following example in your Go application:
-```go
-package main
-
-import (
- "fmt"
- "runtime"
-
- spm "weforge.xyz/Spitfire/SPM"
-)
-
-func main() {
- // Define the packages to download
- specs := []spm.AppIndexEntry{
- {
- Name: "spitfire-launcher",
- Release: "nightly",
- OS: runtime.GOOS,
- Arch: runtime.GOARCH,
- Type: "launcher",
- },
- {
- Name: "spitfire-browser",
- Release: "nightly",
- OS: runtime.GOOS,
- Arch: runtime.GOARCH,
- Type: "browser",
- },
- }
-
- // -- Download --
- // spm.DownloadSpecified(specs) downloads specified packages to temp dir and decompresses them, making them ready for install by running "spm.InstallUpdates()".
- fmt.Println("Starting download and decompression...")
- if err := spm.DownloadSpecified(specs); err != nil {
- fmt.Println("Error downloading packages:", err)
- return
- }
-
- fmt.Println("Download complete. Proceeding with installation...")
-
- // -- Install --
- // Install and Download are separate as you cannot replace running binaries on Windows. So the final move to the correct folder is done by "spm.InstallUpdates()".
- if err := spm.InstallUpdates(); err != nil {
- fmt.Println("Error during installation:", err)
- return
- }
-
- // -- Register --
- // spm.RegisterApp() is primarily used to modify the Windows registry so it recognizes Spitfire Browser as an installed program.
- // You shouldn’t need to run it more than once during installation. Also this function requires administrative privileges on Windows to work correctly.
- if err := spm.RegisterApp(); err != nil {
- fmt.Println("Error registering app:", err)
- return
- }
-
- fmt.Println("Installation completed successfully!")
-
- // -- Run --
- // This function detects the browser binary and runs it. Alternatively, you can also use spm.RunAndWait()
- spm.Run()
-}
-```
-
-
- License
-
-
-
-
-
diff --git a/appindex.go b/appindex.go
index 848d59e..14a77be 100644
--- a/appindex.go
+++ b/appindex.go
@@ -6,46 +6,14 @@ import (
"io"
"net/http"
"os"
- "path/filepath"
- "sort"
"strings"
-
- "gopkg.in/ini.v1"
)
-// AppIndexEntry represents a single entry in an app index.
-type AppIndexEntry struct {
- Name string
- Version string
- Release string // "nightly" / "stable" / etc.
- Arch string // e.g. "amd64", "386"
- OS string // e.g. "windows", "linux"
- Type string // "browser", "addon", "theme", etc.
- DownloadURL string
-}
+const appIndexURL = "https://downloads.sourceforge.net/project/spitfire-browser/APPINDEX"
-// RemoteIndex represents a remote APPINDEX repository.
-type RemoteIndex struct {
- Name string `json:"name"`
- Link string `json:"link"`
-}
-
-var (
- // defaultRemoteIndexes holds the default remote index.
- defaultRemoteIndexes = []RemoteIndex{
- {
- Name: "default",
- Link: "https://downloads.sourceforge.net/project/spitfire-browser/APPINDEX",
- },
- }
- // remoteIndexes holds the current remote indexes in use.
- remoteIndexes = defaultRemoteIndexes
-)
-
-// downloadAppIndex downloads an APPINDEX from the given URL and writes it to dest.
-func downloadAppIndex(url, dest string) error {
+func DownloadAppIndex(dest string) error {
UpdateProgress(0, "Downloading APPINDEX")
- resp, err := http.Get(url)
+ resp, err := http.Get(appIndexURL)
if err != nil {
return err
}
@@ -84,10 +52,25 @@ func downloadAppIndex(url, dest string) error {
return nil
}
-// parseAppIndexFromReader parses an APPINDEX from any io.Reader.
-func parseAppIndexFromReader(r io.Reader) ([]AppIndexEntry, error) {
+type AppIndexEntry struct {
+ Name string
+ Version string
+ Release string // "nightly" / "stable" / etc.
+ Arch string // e.g. "amd64", "386"
+ OS string // e.g. "windows", "linux"
+ Type string // "browser", "addon", "theme", etc.
+ DownloadURL string
+}
+
+func ParseAppIndex(filePath string) ([]AppIndexEntry, error) {
+ file, err := os.Open(filePath)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
var entries []AppIndexEntry
- scanner := bufio.NewScanner(r)
+ scanner := bufio.NewScanner(file)
entry := AppIndexEntry{}
for scanner.Scan() {
@@ -129,222 +112,12 @@ func parseAppIndexFromReader(r io.Reader) ([]AppIndexEntry, error) {
entries = append(entries, entry)
}
- return entries, scanner.Err()
-}
-
-// parseAppIndex reads the APPINDEX file at filePath and parses its contents.
-func parseAppIndex(filePath string) ([]AppIndexEntry, error) {
- file, err := os.Open(filePath)
- if err != nil {
- return nil, err
- }
- defer file.Close()
-
- entries, err := parseAppIndexFromReader(file)
- if err != nil {
- return nil, err
- }
-
- fmt.Printf("[INFO] Total parsed entries from %s: %d\n", filePath, len(entries))
+ // Log all parsed entries
+ fmt.Printf("[INFO] Total parsed entries: %d\n", len(entries))
for _, e := range entries {
fmt.Printf(" - Name: %s, Release: %s, Type: %s, OS: %s, Arch: %s, Version: %s, URL: %s\n",
e.Name, e.Release, e.Type, e.OS, e.Arch, e.Version, e.DownloadURL)
}
- return entries, nil
-}
-
-// saveIndex saves the current list of remote indexes to an INI file located in
-// the spm directory under installDir, but only if it's different from the default.
-func saveIndex() error {
- // Only save if remoteIndexes differs from defaultRemoteIndexes.
- if len(remoteIndexes) == len(defaultRemoteIndexes) {
- same := true
- for i, ri := range remoteIndexes {
- if ri != defaultRemoteIndexes[i] {
- same = false
- break
- }
- }
- if same {
- return nil
- }
- }
-
- installDir, err := GetInstallDir()
- if err != nil {
- return err
- }
- spmDir := filepath.Join(installDir, "spm")
- if err := os.MkdirAll(spmDir, 0755); err != nil {
- return err
- }
- filePath := filepath.Join(spmDir, "sources.ini")
-
- cfg := ini.Empty()
- sec, err := cfg.NewSection("RemoteIndexes")
- if err != nil {
- return err
- }
- // Save each remote index as a key/value pair.
- for _, ri := range remoteIndexes {
- if _, err := sec.NewKey(ri.Name, ri.Link); err != nil {
- return err
- }
- }
-
- return cfg.SaveTo(filePath)
-}
-
-// loadIndex loads the list of remote indexes from an INI file located in
-// the spm directory under installDir. If the file is missing, it sets remoteIndexes to the default.
-func loadIndex() error {
- installDir, err := GetInstallDir()
- if err != nil {
- return err
- }
- spmDir := filepath.Join(installDir, "spm")
- filePath := filepath.Join(spmDir, "sources.ini")
- cfg, err := ini.Load(filePath)
- if err != nil {
- // If file is missing or can't be loaded, use the default.
- remoteIndexes = defaultRemoteIndexes
- return nil
- }
- sec := cfg.Section("RemoteIndexes")
- var loaded []RemoteIndex
- for _, key := range sec.Keys() {
- loaded = append(loaded, RemoteIndex{
- Name: key.Name(),
- Link: key.Value(),
- })
- }
- remoteIndexes = loaded
- return nil
-}
-
-// UpdateIndex downloads fresh APPINDEX files from all remote sources and saves them
-// into the temp directory. If the app is registered, it loads the remote indexes
-// from the INI file (or uses the default if not available) and saves them after updating.
-func UpdateIndex() error {
- tempDir := GetTempDir()
- var sources []RemoteIndex
- if IsRegistered() {
- // Try to load persisted remote indexes.
- if err := loadIndex(); err != nil {
- // If loading fails, fall back to the default remote indexes.
- sources = defaultRemoteIndexes
- } else {
- sources = remoteIndexes
- }
- } else {
- // Not registered: use default remote indexes.
- sources = defaultRemoteIndexes
- }
-
- // Download each APPINDEX file.
- for _, ri := range sources {
- localPath := filepath.Join(tempDir, fmt.Sprintf("appindex_%s.txt", ri.Name))
- if err := downloadAppIndex(ri.Link, localPath); err != nil {
- return fmt.Errorf("[WARN] AppIndex: failed downloading %s: %v", ri.Link, err)
- }
- }
-
- // If registered, save the current remote indexes.
- if IsRegistered() {
- if err := saveIndex(); err != nil {
- return fmt.Errorf("[WARN] AppIndex: failed saving indexes: %v", err)
- }
- }
- return nil
-}
-
-// GetIndex parses APPINDEX data from local files in the temp directory.
-// If a file is missing, it downloads the corresponding APPINDEX first.
-// If the app is registered, it loads remote indexes from the INI file.
-// Otherwise, it uses the default remote index.
-func GetIndex() ([]AppIndexEntry, error) {
- var allEntries []AppIndexEntry
- tempDir := GetTempDir()
- var sources []RemoteIndex
- if IsRegistered() {
- if err := loadIndex(); err != nil {
- sources = defaultRemoteIndexes
- } else {
- sources = remoteIndexes
- }
- } else {
- sources = defaultRemoteIndexes
- }
-
- // For each remote source, ensure the APPINDEX file exists (downloading if needed),
- // then parse its contents.
- for _, ri := range sources {
- localPath := filepath.Join(tempDir, fmt.Sprintf("appindex_%s.txt", ri.Name))
- if _, err := os.Stat(localPath); os.IsNotExist(err) {
- if err := downloadAppIndex(ri.Link, localPath); err != nil {
- return nil, fmt.Errorf("[WARN] AppIndex: failed downloading %s: %v", ri.Link, err)
- }
- }
- entries, err := parseAppIndex(localPath)
- if err != nil {
- return nil, fmt.Errorf("[WARN] AppIndex: failed parsing %s: %v", localPath, err)
- }
- allEntries = append(allEntries, entries...)
- }
- return allEntries, nil
-}
-
-// AddIndex adds a new remote index (name and link) into the list,
-// sorts the list by name, and if the app is registered, saves the updated list.
-func AddIndex(name, link string) error {
- // If registered, load current indexes first.
- if IsRegistered() {
- if err := loadIndex(); err != nil {
- return fmt.Errorf("[WARN] AppIndex: failed loading indexes: %w", err)
- }
- }
-
- ri := RemoteIndex{
- Name: name,
- Link: link,
- }
- remoteIndexes = append(remoteIndexes, ri)
- sort.Slice(remoteIndexes, func(i, j int) bool {
- return remoteIndexes[i].Name < remoteIndexes[j].Name
- })
-
- // If registered, persist the changes.
- if IsRegistered() {
- if err := saveIndex(); err != nil {
- return fmt.Errorf("[WARN] AppIndex: failed saving indexes: %w", err)
- }
- }
- return nil
-}
-
-// RemoveIndex removes any remote index with the given name from the list,
-// and if the app is registered, saves the updated list.
-func RemoveIndex(name string) error {
- // If registered, load current indexes first.
- if IsRegistered() {
- if err := loadIndex(); err != nil {
- return fmt.Errorf("[WARN] AppIndex: failed loading indexes: %w", err)
- }
- }
-
- var updated []RemoteIndex
- for _, ri := range remoteIndexes {
- if ri.Name != name {
- updated = append(updated, ri)
- }
- }
- remoteIndexes = updated
-
- // If registered, persist the changes.
- if IsRegistered() {
- if err := saveIndex(); err != nil {
- return fmt.Errorf("[WARN] AppIndex: failed saving indexes: %w", err)
- }
- }
- return nil
+
+ return entries, scanner.Err()
}
diff --git a/auto.go b/auto.go
index d544a44..92e574a 100644
--- a/auto.go
+++ b/auto.go
@@ -2,6 +2,7 @@ package spm
import (
"fmt"
+ "os"
"path/filepath"
)
@@ -9,19 +10,22 @@ import (
// but not yet moved to the final install location, cuz Windows has this stupid file locking mechanism
var pendingUpdates []AppIndexEntry
-// DownloadUpdates downloads the APPINDEX file, parses it, compares against
+// AutoDownloadUpdates downloads the APPINDEX file, parses it, compares against
// currently installed packages, and if it finds a newer version, downloads
-// and decompresses it into a temporary folder. The result is stored in pendingUpdates, so it can be used by InstallUpdates().
-func DownloadUpdates() error {
+// and decompresses it into a temporary folder. The result is stored in pendingUpdates, so it can be used by AutoInstallUpdates().
+func AutoDownloadUpdates() error {
// 1) Download the APPINDEX file to a temporary location
- err := UpdateIndex()
+ appIndexPath := filepath.Join(os.TempDir(), "APPINDEX")
+ fmt.Println("[INFO] Starting APPINDEX download to:", appIndexPath)
+ err := DownloadAppIndex(appIndexPath)
if err != nil {
return fmt.Errorf("[ERROR] Failed to download APPINDEX: %w", err)
}
fmt.Println("[INFO] APPINDEX downloaded successfully")
// 2) Parse the APPINDEX file
- entries, err := GetIndex()
+ fmt.Println("[INFO] Parsing APPINDEX file:", appIndexPath)
+ entries, err := ParseAppIndex(appIndexPath)
if err != nil {
return fmt.Errorf("[ERROR] Failed to parse APPINDEX: %w", err)
}
@@ -80,7 +84,7 @@ func DownloadUpdates() error {
downloadDir := GetTempDir()
fmt.Printf("[INFO] Downloading package '%s' to temporary folder: %s\n", matchingEntry.Name, downloadDir)
- err = DownloadPackageFromAppIndex(matchingEntry.Name, matchingEntry.Release, matchingEntry.Type, downloadDir)
+ err = DownloadPackageFromAppIndex(appIndexPath, matchingEntry.Name, matchingEntry.Release, matchingEntry.Type, downloadDir)
if err != nil {
return fmt.Errorf("[ERROR] Failed to download package '%s': %w", matchingEntry.Name, err)
}
@@ -95,7 +99,7 @@ func DownloadUpdates() error {
}
fmt.Printf("[INFO] Package '%s' decompressed successfully to: %s\n", matchingEntry.Name, tempDir)
- // 7) Store in pendingUpdates so that InstallUpdates can finish the job
+ // 7) Store in pendingUpdates so that AutoInstallUpdates can finish the job
fmt.Printf("[INFO] Adding '%s' to pending updates\n", matchingEntry.Name)
pendingUpdates = append(pendingUpdates, AppIndexEntry{
Name: matchingEntry.Name,
@@ -107,13 +111,13 @@ func DownloadUpdates() error {
})
}
- fmt.Println("[INFO] DownloadUpdates completed successfully")
+ fmt.Println("[INFO] AutoDownloadUpdates completed successfully")
return nil
}
-// InstallUpdates installs any packages that were downloaded and decompressed by DownloadUpdates.
+// AutoInstallUpdates installs any packages that were downloaded and decompressed by AutoDownloadUpdates.
// It moves files from their temp directories to the final location and updates installed.ini.
-func InstallUpdates() error {
+func AutoInstallUpdates() error {
installDir, err := GetInstallDir()
if err != nil {
return err
@@ -142,7 +146,7 @@ func InstallUpdates() error {
}
// 5) Finalize
- err = finalizeInstall(entry.Name, entry.Release, entry.Version, entry.Arch, entry.OS)
+ err = FinalizeInstall(entry.Name, entry.Release, entry.Version, entry.Arch, entry.OS)
if err != nil {
return fmt.Errorf("failed to finalize install for %s: %w", entry.Name, err)
}
@@ -152,15 +156,18 @@ func InstallUpdates() error {
return nil
}
-func DownloadSpecified(specs []AppIndexEntry) error {
+func AutoDownloadSpecified(specs []AppIndexEntry) error {
// 1) Download the APPINDEX file to a temporary location
- if err := UpdateIndex(); err != nil {
+ appIndexPath := filepath.Join(os.TempDir(), "APPINDEX")
+ fmt.Println("[INFO] Starting APPINDEX download to:", appIndexPath)
+ if err := DownloadAppIndex(appIndexPath); err != nil {
return fmt.Errorf("[ERROR] Failed to download APPINDEX: %w", err)
}
fmt.Println("[INFO] APPINDEX downloaded successfully")
// 2) Parse the APPINDEX file
- entries, err := GetIndex()
+ fmt.Println("[INFO] Parsing APPINDEX file:", appIndexPath)
+ entries, err := ParseAppIndex(appIndexPath)
if err != nil {
return fmt.Errorf("[ERROR] Failed to parse APPINDEX: %w", err)
}
@@ -196,27 +203,29 @@ func DownloadSpecified(specs []AppIndexEntry) error {
}
fmt.Printf("[INFO] Found matching APPINDEX entry: %+v\n", *matchingEntry)
- updateNeeded, err := IsUpdateNeeded(
- installDir,
- matchingEntry.Name,
- matchingEntry.Release,
- matchingEntry.Version,
- matchingEntry.Arch,
- matchingEntry.OS,
- )
- if err != nil {
- return fmt.Errorf("[ERROR] Failed to check if update is needed for %s: %w", matchingEntry.Name, err)
- }
+ // // Check if an update is needed
+ // updateNeeded, err := IsUpdateNeeded(
+ // installDir,
+ // matchingEntry.Name,
+ // matchingEntry.Release,
+ // matchingEntry.Version,
+ // matchingEntry.Arch,
+ // matchingEntry.OS,
+ // )
+ // if err != nil {
+ // return fmt.Errorf("[ERROR] Failed to check if update is needed for %s: %w", matchingEntry.Name, err)
+ // }
- if !updateNeeded {
- fmt.Printf("[INFO] No update needed for package '%s'\n", matchingEntry.Name)
- continue
- }
+ // if !updateNeeded {
+ // fmt.Printf("[INFO] No update needed for package '%s'\n", matchingEntry.Name)
+ // continue
+ // }
// 5) Download the package
downloadDir := GetTempDir()
fmt.Printf("[INFO] Downloading package '%s' to temporary folder: %s\n", matchingEntry.Name, downloadDir)
if err := DownloadPackageFromAppIndex(
+ appIndexPath,
matchingEntry.Name,
matchingEntry.Release,
matchingEntry.Type,
@@ -242,7 +251,7 @@ func DownloadSpecified(specs []AppIndexEntry) error {
}
fmt.Printf("[INFO] Package '%s' decompressed successfully to: %s\n", matchingEntry.Name, tempDir)
- // Add to pendingUpdates for InstallUpdates
+ // 7) Store in pendingUpdates for AutoInstallUpdates
fmt.Printf("[INFO] Adding '%s' to pending updates\n", matchingEntry.Name)
pendingUpdates = append(pendingUpdates, *matchingEntry)
}
diff --git a/decompress.go b/decompress.go
index 00003e2..7f7a207 100644
--- a/decompress.go
+++ b/decompress.go
@@ -108,11 +108,7 @@ func decompressTarGz(srcFile, destDir string, updateProgress func(int, string))
// Update progress after extracting each file.
if updateProgress != nil {
percent := int((progressReader.BytesRead * 100) / totalSize)
- name := header.Name
- if len(name) > 50 {
- name = name[len(name)-50:]
- }
- updateProgress(percent, fmt.Sprintf("Extracted: %s", name))
+ updateProgress(percent, fmt.Sprintf("Extracted: %s", header.Name))
}
}
diff --git a/download.go b/download.go
index c6464f2..30d239c 100644
--- a/download.go
+++ b/download.go
@@ -11,9 +11,9 @@ import (
)
// DownloadPackageFromAppIndex selects and downloads the correct package from the APPINDEX.
-func DownloadPackageFromAppIndex(packageName string, release string, pkgType string, destDir string) error {
+func DownloadPackageFromAppIndex(appIndexPath string, packageName string, release string, pkgType string, destDir string) error {
// Parse the APPINDEX
- entries, err := GetIndex()
+ entries, err := ParseAppIndex(appIndexPath)
if err != nil {
return fmt.Errorf("failed to parse APPINDEX: %w", err)
}
@@ -99,8 +99,8 @@ func DownloadPackageFromAppIndex(packageName string, release string, pkgType str
expectedFilePath := filepath.Join(destDir, expectedFileName)
- // I dont know why is this happening, I dont want to know but sometimes some process is helding up the downloaded files so thats why it retries here
- maxRetries := 10
+ // I dont know why is this happening, I dont want to know but sometimes some process is helding up the donwloaded files so thats why it retries here
+ maxRetries := 5
for i := 0; i < maxRetries; i++ {
err = os.Rename(downloadedFilePath, expectedFilePath)
if err == nil {
@@ -115,7 +115,7 @@ func DownloadPackageFromAppIndex(packageName string, release string, pkgType str
f.Close()
if i < maxRetries-1 {
- time.Sleep(250 * time.Millisecond) // Wait before retrying
+ time.Sleep(500 * time.Millisecond) // Wait before retrying
}
}
diff --git a/go.mod b/go.mod
index f4c1524..8b67881 100644
--- a/go.mod
+++ b/go.mod
@@ -1,12 +1,7 @@
module weforge.xyz/Spitfire/SPM
-go 1.23.0
+go 1.21
-toolchain go1.24.1
-
-require (
- golang.org/x/sys v0.31.0
- gopkg.in/ini.v1 v1.67.0
-)
+require gopkg.in/ini.v1 v1.67.0
require github.com/stretchr/testify v1.10.0 // indirect
diff --git a/go.sum b/go.sum
index bd54818..be248fb 100644
--- a/go.sum
+++ b/go.sum
@@ -4,8 +4,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
-golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/install.go b/install.go
index a8d8521..9fbf274 100644
--- a/install.go
+++ b/install.go
@@ -287,8 +287,8 @@ func copyFile(src, dst string) error {
return os.Chmod(dst, info.Mode())
}
-// finalizeInstall finalizes the installation by updating installed.ini.
-func finalizeInstall(packageName, release, version, arch, osName string) error {
+// FinalizeInstall finalizes the installation by updating installed.ini.
+func FinalizeInstall(packageName, release, version, arch, osName string) error {
installDir, err := GetInstallDir()
if err != nil {
return err
diff --git a/installed_pacakges.go b/installed_pacakges.go
index 9f73aea..1f89eae 100644
--- a/installed_pacakges.go
+++ b/installed_pacakges.go
@@ -72,16 +72,6 @@ func saveInstalledPackages(installDir string, pkgs []AppIndexEntry) error {
section.Key("V").SetValue(pkg.Version)
section.Key("R").SetValue(pkg.Release)
section.Key("o").SetValue(pkg.Type)
-
- // Save arch if different from current runtime architecture
- if pkg.Arch != runtime.GOARCH {
- section.Key("A").SetValue(pkg.Arch)
- }
-
- // Save OS if different from current runtime OS
- if pkg.OS != runtime.GOOS {
- section.Key("p").SetValue(pkg.OS)
- }
}
return cfg.SaveTo(installedFile)
diff --git a/register_unix.go b/register_unix.go
index f9e35c9..6568edd 100644
--- a/register_unix.go
+++ b/register_unix.go
@@ -4,34 +4,14 @@
package spm
-import (
- "fmt"
- "os"
- "path/filepath"
-)
+import "fmt"
// RegisterApp is not supported on non-Windows platforms.
func RegisterApp() error {
- return fmt.Errorf("[WARN] RegisterApp() is only available on Windows")
+ return fmt.Errorf("RegisterApp is only available on Windows")
}
// UnregisterApp is not supported on non-Windows platforms.
func UnregisterApp() error {
- return fmt.Errorf("[WARN] UnregisterApp() is only available on Windows")
-}
-
-// IsRegistered returns true if the application is detected as installed.
-// On Linux, we assume it is installed if the main executable exists in the install directory.
-func IsRegistered() bool {
- installDir, err := GetInstallDir()
- if err != nil {
- return false
- }
-
- // Assume the executable is named "spitfire" and is located in installDir.
- exePath := filepath.Join(installDir, "browser", "spitfire")
- if _, err := os.Stat(exePath); err == nil {
- return true
- }
- return false
+ return fmt.Errorf("UnregisterApp is only available on Windows")
}
diff --git a/register_win.go b/register_win.go
index 206f0ae..b2cf47f 100644
--- a/register_win.go
+++ b/register_win.go
@@ -10,7 +10,7 @@ import (
"golang.org/x/sys/windows/registry"
)
-// RegisterApp writes the necessary registry keys, making it appear as officially installed app
+// RegisterApp writes the necessary registry keys, making it appear as offically installed app
func RegisterApp() error {
exePath, err := GetInstallDir()
if err != nil {
@@ -133,15 +133,3 @@ func deleteRegistryTree(root registry.Key, path string) error {
// Finally, delete the (now empty) key.
return registry.DeleteKey(root, path)
}
-
-// IsRegistered returns true if the application is registered (installed) in the registry.
-func IsRegistered() bool {
- // Try to open the uninstall key with read-only access.
- key, err := registry.OpenKey(registry.LOCAL_MACHINE, `Software\Microsoft\Windows\CurrentVersion\Uninstall\SpitfireBrowser`, registry.READ)
- if err != nil {
- // If the key cannot be opened, assume the app is not registered.
- return false
- }
- defer key.Close()
- return true
-}
diff --git a/run_unix.go b/run_unix.go
index aa580b2..cc82b79 100644
--- a/run_unix.go
+++ b/run_unix.go
@@ -9,6 +9,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
"syscall"
)
@@ -20,6 +21,9 @@ func Run() error {
}
exePath := filepath.Join(installDir, "browser", "spitfire.exe")
+ if runtime.GOOS != "windows" {
+ exePath = filepath.Join(installDir, "browser", "spitfire")
+ }
cmd := exec.Command(exePath)
cmd.Dir = filepath.Join(installDir, "browser")
diff --git a/run_win.go b/run_win.go
index 706b6d4..d1f2b38 100644
--- a/run_win.go
+++ b/run_win.go
@@ -9,10 +9,8 @@ import (
"os"
"os/exec"
"path/filepath"
- "strings"
- "time"
-
- "golang.org/x/sys/windows"
+ "runtime"
+ "syscall"
)
// Run locates and starts the installed Spitfire browser without waiting for it to exit.
@@ -23,6 +21,9 @@ func Run() error {
}
exePath := filepath.Join(installDir, "browser", "spitfire.exe")
+ if runtime.GOOS != "windows" {
+ exePath = filepath.Join(installDir, "browser", "spitfire")
+ }
cmd := exec.Command(exePath)
cmd.Dir = filepath.Join(installDir, "browser")
@@ -36,6 +37,7 @@ func RunAndWait() error {
return fmt.Errorf("failed to get install directory: %w", err)
}
+ // Construct the browser executable path
exePath := filepath.Join(installDir, "browser", "spitfire.exe")
if _, err := os.Stat(exePath); err != nil {
return fmt.Errorf("browser executable not found at %s: %w", exePath, err)
@@ -44,29 +46,23 @@ func RunAndWait() error {
cmd := exec.Command(exePath)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
- cmd.Dir = filepath.Join(installDir, "browser")
- // Create job object starting the process
- job, err := windows.CreateJobObject(nil, nil)
- if err != nil {
- return fmt.Errorf("failed to create job object: %w", err)
+ // Use CREATE_NEW_PROCESS_GROUP flag for Windows
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
}
- defer windows.CloseHandle(job)
fmt.Printf("Starting browser: %s\n", exePath)
if err := cmd.Start(); err != nil {
return fmt.Errorf("failed to start browser: %w", err)
}
- for {
- cmd := exec.Command("tasklist", "/FI", "IMAGENAME eq spitfire.exe")
- output, _ := cmd.Output()
- if !strings.Contains(string(output), "spitfire.exe") {
- break
- }
- time.Sleep(1 * time.Second)
+ fmt.Printf("Browser process started with PID %d\n", cmd.Process.Pid)
+
+ if err := cmd.Wait(); err != nil {
+ return fmt.Errorf("browser exited with error: %w", err)
}
- fmt.Println("Browser exited.")
+ fmt.Println("Browser exited successfully.")
return nil
}