|
|
@@ -6,11 +6,12 @@ import ( |
|
|
|
"runtime" |
|
|
|
"os" |
|
|
|
"io" |
|
|
|
"fmt" |
|
|
|
"log" |
|
|
|
"errors" |
|
|
|
"archive/zip" |
|
|
|
"path/filepath" |
|
|
|
"flag" |
|
|
|
"time" |
|
|
|
) |
|
|
|
|
|
|
|
const ( |
|
|
@@ -27,49 +28,64 @@ var ( |
|
|
|
PlatformStream string |
|
|
|
UpdateServer string |
|
|
|
TargetBinary string |
|
|
|
Delay time.Duration |
|
|
|
IsLogged bool |
|
|
|
) |
|
|
|
|
|
|
|
func init() { |
|
|
|
fmt.Println("RXSM Updater version", RXSMUpdaterVersion) |
|
|
|
fmt.Println("This program updates RXSM headlessly. Use rxsm-updater --help to view advanced features") |
|
|
|
fmt.Println(os.Args) |
|
|
|
log.Println("RXSM Updater version", RXSMUpdaterVersion) |
|
|
|
log.Println("This program updates RXSM headlessly. Use rxsm-updater --help to view advanced features") |
|
|
|
log.Println(os.Args) |
|
|
|
flag.StringVar(&Zipfile, "zip", DefaultZipFile, "The zipfile to extract from (and download to, in unattended mode)") |
|
|
|
flag.StringVar(&Target, "target", "", "The directory to target for the update (the directory containing RXSM)") |
|
|
|
flag.BoolVar(&Unattended, "unattended", false, "Download & extract the RXSM update (WIP)") |
|
|
|
flag.StringVar(&PlatformStream, "stream", "release", "The update stream to use when retrieving updates in unattended mode") |
|
|
|
flag.StringVar(&UpdateServer, "server", DefaultUpdateServer, "The web server to use for retrieving update information") |
|
|
|
flag.DurationVar(&Delay, "wait", 0, "Time to wait before starting") |
|
|
|
flag.BoolVar(&IsLogged, "log", false, "Send output to log") |
|
|
|
} |
|
|
|
|
|
|
|
func main() { |
|
|
|
flag.Parse() |
|
|
|
if IsLogged { |
|
|
|
f, _ := os.Create("rxsm-updater.log") |
|
|
|
log.SetOutput(f) |
|
|
|
log.Println("RXSM Updater version", RXSMUpdaterVersion) |
|
|
|
log.Println("This program updates RXSM headlessly. Use rxsm-updater --help to view advanced features") |
|
|
|
log.Println(os.Args) |
|
|
|
} |
|
|
|
if Delay != 0 { |
|
|
|
log.Println("Waiting", Delay.Seconds(), "second(s)") |
|
|
|
time.Sleep(Delay) |
|
|
|
} |
|
|
|
if Unattended { |
|
|
|
fmt.Println("Attempting WIP Unattended update") |
|
|
|
fmt.Println("This is not advised, and will fail if an updater update is necessary") |
|
|
|
log.Println("Attempting WIP Unattended update") |
|
|
|
log.Println("This is not advised, and will fail if an updater update is necessary") |
|
|
|
URL, isUpdatable, ok := CheckForUpdate(UpdateServer, "", runtime.GOOS+"/"+runtime.GOARCH+"/"+PlatformStream) |
|
|
|
if !(ok && isUpdatable && URL != "") { |
|
|
|
fmt.Println("No update found") |
|
|
|
log.Println("No update found") |
|
|
|
return |
|
|
|
} |
|
|
|
downloadErr := DownloadRXSMUpdate(URL, func(int, string){}) |
|
|
|
if downloadErr != nil { |
|
|
|
fmt.Println(downloadErr) |
|
|
|
log.Println(downloadErr) |
|
|
|
return |
|
|
|
} |
|
|
|
proc, forkErr := ForkRXSMUpdate() |
|
|
|
if forkErr != nil { |
|
|
|
fmt.Println(forkErr) |
|
|
|
log.Println(forkErr) |
|
|
|
return |
|
|
|
} |
|
|
|
fmt.Println("Extraction forked to", proc.Pid) |
|
|
|
log.Println("Extraction forked to", proc.Pid) |
|
|
|
} else { |
|
|
|
fmt.Println("Installing from", Zipfile) |
|
|
|
log.Println("Installing from", Zipfile) |
|
|
|
installErr := InstallRXSMUpdate(func(int, string){}) |
|
|
|
if installErr != nil { |
|
|
|
fmt.Println(installErr) |
|
|
|
log.Println(installErr) |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
fmt.Println("Operation complete") |
|
|
|
log.Println("Operation complete") |
|
|
|
// TODO: implement callback for Qt window |
|
|
|
} |
|
|
|
|
|
|
@@ -80,17 +96,17 @@ func DownloadRXSMUpdateQuiet(URL string) { |
|
|
|
func DownloadRXSMUpdate(URL string, statusCallback func(progress int, description string)) (error){ |
|
|
|
// progress is out of 100 |
|
|
|
statusCallback(25, "Downloading") |
|
|
|
fmt.Println("Downloading update from "+URL) |
|
|
|
log.Println("Downloading update from "+URL) |
|
|
|
f, createErr := os.Create(Zipfile) |
|
|
|
if createErr != nil { |
|
|
|
fmt.Println("Error creating temporary update file") |
|
|
|
log.Println("Error creating temporary update file") |
|
|
|
statusCallback(-1, "Error creating update temporary file") |
|
|
|
return createErr |
|
|
|
} |
|
|
|
defer f.Close() |
|
|
|
ok := DownloadUpdate(URL, f) |
|
|
|
if !ok { |
|
|
|
fmt.Println("Error downloading update") |
|
|
|
log.Println("Error downloading update") |
|
|
|
statusCallback(-1, "Download failed") |
|
|
|
return errors.New("download failed in update API") |
|
|
|
} |
|
|
@@ -99,16 +115,16 @@ func DownloadRXSMUpdate(URL string, statusCallback func(progress int, descriptio |
|
|
|
f.Seek(0,0) |
|
|
|
fStat, statErr := f.Stat() |
|
|
|
if statErr != nil { |
|
|
|
fmt.Println("Error getting download temp file stat") |
|
|
|
log.Println("Error getting download temp file stat") |
|
|
|
return statErr |
|
|
|
} |
|
|
|
fmt.Println("Downloaded", fStat.Size(), "bytes") |
|
|
|
log.Println("Downloaded", fStat.Size(), "bytes") |
|
|
|
statusCallback(75, "Extracting Updater") |
|
|
|
// TODO: implement way to have this actually work |
|
|
|
zipFile, zipErr := zip.NewReader(f, fStat.Size()) |
|
|
|
if zipErr != nil { |
|
|
|
fmt.Println("Error creating zip reader") |
|
|
|
fmt.Println(zipErr) |
|
|
|
log.Println("Error creating zip reader") |
|
|
|
log.Println(zipErr) |
|
|
|
return zipErr |
|
|
|
} |
|
|
|
for _, f := range zipFile.File { |
|
|
@@ -125,19 +141,19 @@ func DownloadRXSMUpdate(URL string, statusCallback func(progress int, descriptio |
|
|
|
if len(filename) >= len(updaterFilename) && filename[:len(updaterFilename)] == updaterFilename { |
|
|
|
fileReadCloser, openErr := f.Open() |
|
|
|
if openErr != nil { |
|
|
|
fmt.Println("Error opening updater in zip archive") |
|
|
|
log.Println("Error opening updater in zip archive") |
|
|
|
return openErr |
|
|
|
} |
|
|
|
defer fileReadCloser.Close() |
|
|
|
destFile, createErr := os.Create(TargetBinary) |
|
|
|
if createErr != nil { |
|
|
|
fmt.Println("Error creating updater file") |
|
|
|
log.Println("Error creating updater file") |
|
|
|
return createErr |
|
|
|
} |
|
|
|
defer destFile.Close() |
|
|
|
_, copyErr := io.Copy(destFile, fileReadCloser) |
|
|
|
if copyErr != nil { |
|
|
|
fmt.Println("Error copying/extracting updater") |
|
|
|
log.Println("Error copying/extracting updater") |
|
|
|
return copyErr |
|
|
|
} |
|
|
|
} |
|
|
@@ -158,7 +174,7 @@ func ForkRXSMUpdate() (process *os.Process, err error) { |
|
|
|
func InstallRXSMUpdate(statusCallback func(progress int, description string)) (error){ |
|
|
|
f, openErr := os.Open(Zipfile) |
|
|
|
if openErr != nil { |
|
|
|
fmt.Println("Error opening zip file") |
|
|
|
log.Println("Error opening zip file") |
|
|
|
statusCallback(-1, "Opening zip file failed") |
|
|
|
return openErr |
|
|
|
} |
|
|
@@ -167,13 +183,13 @@ func InstallRXSMUpdate(statusCallback func(progress int, description string)) (e |
|
|
|
f.Seek(0,0) |
|
|
|
fStat, statErr := f.Stat() |
|
|
|
if statErr != nil { |
|
|
|
fmt.Println("Error retrieving file stats") |
|
|
|
log.Println("Error retrieving file stats") |
|
|
|
statusCallback(-1, "Extracting zip file failed") |
|
|
|
return statErr |
|
|
|
} |
|
|
|
unpackErr := unpackRXSMInstall(f, fStat.Size(), func(p int, d string){statusCallback(1, d)}) |
|
|
|
if unpackErr != nil { |
|
|
|
fmt.Println("Error extracting update") |
|
|
|
log.Println("Error extracting update") |
|
|
|
statusCallback(-1, "Unpacking failed") |
|
|
|
return unpackErr |
|
|
|
} |
|
|
@@ -181,7 +197,7 @@ func InstallRXSMUpdate(statusCallback func(progress int, description string)) (e |
|
|
|
// TODO: is there installation required? |
|
|
|
rmErr := os.Remove(Zipfile) |
|
|
|
if rmErr != nil { |
|
|
|
fmt.Println("Error removing download file") |
|
|
|
log.Println("Error removing download file") |
|
|
|
statusCallback(-1, "Installing failed") |
|
|
|
return rmErr |
|
|
|
} |
|
|
@@ -230,7 +246,7 @@ func unpackRXSMInstall(reader io.ReaderAt, size int64, statusCallback func(progr |
|
|
|
filename = filepath.Join(Target, filename) |
|
|
|
dirErr := os.MkdirAll(filepath.Dir(filename), os.ModeDir | os.ModePerm) |
|
|
|
if dirErr != nil { |
|
|
|
fmt.Println("Dir err "+filepath.Dir(filename)) |
|
|
|
log.Println("Dir err "+filepath.Dir(filename)) |
|
|
|
return dirErr |
|
|
|
} |
|
|
|
newFile, createErr := os.Create(filename) |
|
|
|