131 lines
3.4 KiB
Go
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
|
|
}
|