Installer/installer.go
partisan b403befe74
Some checks failed
/ test-on-windows (push) Failing after 9s
/ test-on-alpine (push) Successful in 1m14s
fixed windows bugs
2025-01-21 23:31:53 +01:00

131 lines
3.4 KiB
Go

package main
import (
"fmt"
"path/filepath"
"spitfire-installer/spm"
)
// Installer manages the download, decompression, and installation processes.
type Installer struct {
// Progress info from SPM
Progress int
Task string
// Internal states
IsDownloading bool
IsInstalling bool
DoneDownload bool
DoneInstall bool
LastError error
PendingInstall bool
// Paths
DownloadDir string
TempDir string
}
// NewInstaller creates a new Installer with initial state.
func NewInstaller() *Installer {
return &Installer{}
}
// StartDownloadDecompress starts the download and decompression in a background goroutine.
func (inst *Installer) StartDownloadDecompress() {
inst.IsDownloading = true
go func() {
defer func() {
inst.IsDownloading = false
inst.DoneDownload = (inst.LastError == nil)
// If user requested install while we were downloading (PendingInstall),
// automatically do the install now that we're done decompressing.
if inst.PendingInstall && inst.DoneDownload && !inst.IsInstalling && !inst.DoneInstall {
inst.doFinalInstall()
}
}()
spm.UpdateProgress(0, "Preparing to download...")
inst.DownloadDir = spm.GetTempDownloadDir()
// 1) Download APPINDEX
appIndexPath := filepath.Join(inst.DownloadDir, "APPINDEX")
spm.UpdateProgress(0, "Downloading APPINDEX")
if err := spm.DownloadAppIndex(appIndexPath); err != nil {
inst.LastError = err
return
}
// 2) Download package
packageName := "spitfire-browser"
release := "nightly"
spm.UpdateProgress(0, "Downloading package...")
if err := spm.DownloadPackageFromAppIndex(appIndexPath, packageName, release, inst.DownloadDir); err != nil {
inst.LastError = err
return
}
// 3) Decompress
spm.UpdateProgress(0, "Decompressing...")
tempDir, err := spm.DecompressPackage(inst.DownloadDir)
if err != nil {
inst.LastError = err
return
}
inst.TempDir = tempDir
}()
}
// FinalInstall is called by the UI to request installation.
// If download is done, it runs immediately, otherwise sets PendingInstall=true.
func (inst *Installer) FinalInstall() {
// Already installed or installing => ignore repeated calls
if inst.IsInstalling || inst.DoneInstall {
return
}
// If not done downloading, just mark that we want to install once finished
if !inst.DoneDownload {
fmt.Println("Cannot install now: download and decompression not complete -> pending install.")
inst.PendingInstall = true
return
}
// Otherwise, go ahead and install now
inst.doFinalInstall()
}
// doFinalInstall does the actual file move and sets states
func (inst *Installer) doFinalInstall() {
inst.IsInstalling = true
inst.PendingInstall = false // we are fulfilling the install now
go func() {
defer func() {
inst.IsInstalling = false
inst.DoneInstall = (inst.LastError == nil)
}()
// Generate default install directory
installDir, err := spm.GetDefaultInstallDir()
if err != nil {
inst.LastError = fmt.Errorf("failed to determine default install directory: %w", err)
return
}
// Move files
spm.UpdateProgress(0, "Installing...")
if err := spm.MoveFilesToInstallDir(inst.TempDir, installDir); err != nil {
inst.LastError = err
return
}
spm.UpdateProgress(100, "Installation complete!")
}()
}
// PollProgress fetches the latest progress and task from SPM.
func (inst *Installer) PollProgress() {
p, t := spm.GetProgress()
inst.Progress, inst.Task = p, t
}