Skip to content

Commit 3ccb883

Browse files
authored
fix: merge windows tray functionality into backrest.exe for single binary install on windows (#903)
1 parent 25d2771 commit 3ccb883

File tree

6 files changed

+30
-70
lines changed

6 files changed

+30
-70
lines changed

.goreleaser.yaml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ builds:
2525
- CGO_ENABLED=0
2626
goos:
2727
- darwin
28-
- windows
2928
- freebsd
3029
goarch:
3130
- amd64
@@ -44,18 +43,17 @@ builds:
4443
- arm
4544
ldflags:
4645
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
47-
- id: backrestmon
48-
main: ./cmd/backrestmon
49-
binary: backrest-windows-tray
46+
- id: windows
47+
main: ./cmd/backrest
5048
env:
5149
- CGO_ENABLED=1
52-
- GO111MODULE=on
53-
ldflags: -H=windowsgui
5450
goos:
5551
- windows
5652
goarch:
5753
- amd64
5854
- arm64
55+
ldflags:
56+
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -H windowsgui
5957

6058
archives:
6159
- format: tar.gz

build/windows/installer.iss

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#define B "Backrest"
2-
#define TrayExe "backrest-windows-tray.exe"
32
#define Website "https://github.com/garethgeorge/backrest/"
43
; The following is needed to extract the version from the change log.
54
; If the application executable had the version info, then could use built-in GetVersion* functions.
@@ -65,13 +64,12 @@ Name: "port9902"; Description: "9902"; GroupDescription: "{#PortDesc}"; Flags: e
6564
; but doing it the same way in all cases for consistency.
6665
Source: "LICENSE"; DestDir: "{app}"; Flags: ignoreversion; BeforeInstall: StopBackrest
6766
Source: "icon.ico"; DestDir: "{app}"; Flags: ignoreversion
68-
Source: "{#TrayExe}"; DestDir: "{app}"; Flags: ignoreversion
6967
Source: "backrest.exe"; DestDir: "{app}"; Flags: ignoreversion
7068

7169
[Icons]
7270
; For user install mode only.
73-
Name: "{autostartup}\{#B} systray"; Filename: "{app}\{#TrayExe}"; Parameters: "{code:GetPortParam}"; IconFilename: "{app}\icon.ico"; Check: IsUserInstallMode
74-
Name: "{group}\{#B} systray"; Filename: "{app}\{#TrayExe}"; Parameters: "{code:GetPortParam}"; IconFilename: "{app}\icon.ico"; Check: IsUserInstallMode
71+
Name: "{autostartup}\{#B} systray"; Filename: "{app}\backrest.exe"; Parameters: "--windows-tray {code:GetPortParam}"; IconFilename: "{app}\icon.ico"; Check: IsUserInstallMode
72+
Name: "{group}\{#B} systray"; Filename: "{app}\backrest.exe"; Parameters: "--windows-tray {code:GetPortParam}"; IconFilename: "{app}\icon.ico"; Check: IsUserInstallMode
7573
; For both modes.
7674
Name: "{group}\{#B}{code:GetIconSuffix}"; Filename: "http://localhost:{code:GetPort}/"; IconFilename: "{app}\icon.ico"
7775
Name: "{group}\{#B} website"; Filename: "{#Website}"
@@ -84,7 +82,7 @@ PrivilegesRequiredOverrideAllUsers=Install &system-wide with administrative priv
8482
[Run]
8583
; Use Task Scheduler to run Backrest elevated. The 30s delay is needed to avoid an issue with tray icon being broken.
8684
; The double-quotes escape double-quotes inside the parameter. The backslash escapes double-quotes inside the -Command block.
87-
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -Command ""$t = New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME ; $t.Delay = 'PT30S'; $s = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries; $s.ExecutionTimeLimit = 'PT0S'; Register-ScheduledTask -Force -TaskName '{#B}' -RunLevel Highest -Trigger $t -Action $(New-ScheduledTaskAction -Execute \""{app}\{#TrayExe}\"" -Argument '--bind-address 127.0.0.1:9897' -WorkingDirectory '{app}') -Settings $s ; Start-ScheduledTask -TaskName '{#B}'"" "; Flags: runascurrentuser logoutput runhidden; Tasks: adminstartcurrent; Check: IsAdminInstallMode
85+
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -Command ""$t = New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME ; $t.Delay = 'PT30S'; $s = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries; $s.ExecutionTimeLimit = 'PT0S'; Register-ScheduledTask -Force -TaskName '{#B}' -RunLevel Highest -Trigger $t -Action $(New-ScheduledTaskAction -Execute \""{app}\backrest.exe\"" -Argument '--windows-tray --bind-address 127.0.0.1:9897' -WorkingDirectory '{app}') -Settings $s ; Start-ScheduledTask -TaskName '{#B}'"" "; Flags: runascurrentuser logoutput runhidden; Tasks: adminstartcurrent; Check: IsAdminInstallMode
8886
; System user task. No need for systray here, and running it without returning control is the only way to stop it gracefully later.
8987
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -Command ""$s = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries; $s.ExecutionTimeLimit = 'PT0S'; Register-ScheduledTask -Force -TaskName '{#B}' -RunLevel Highest -User System -Trigger $(New-ScheduledTaskTrigger -AtStartup) -Action $(New-ScheduledTaskAction -Execute \""{app}\backrest.exe\"" -Argument '--bind-address 127.0.0.1:9897' -WorkingDirectory '{app}') -Settings $s ; Start-ScheduledTask -TaskName '{#B}'"" "; Flags: runascurrentuser logoutput runhidden; Tasks: adminstartsystem; Check: IsAdminInstallMode
9088
; PATH
@@ -94,7 +92,7 @@ Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -Command ""$new
9492
#define PathDelCmd "-ExecutionPolicy Bypass -Command """"$newp = '{app}'; $a = [Environment]::GetEnvironmentVariable('PATH', '{code:GetEnvTarget}') -split ';' ; if ($a -contains $newp) {{ echo 'Removing from PATH'; $path = ($a | Where-Object {{ $_ -ne $newp }) -join ';' ; [Environment]::SetEnvironmentVariable('PATH', $path, '{code:GetEnvTarget}') }"""" "
9593
Filename: "powershell.exe"; Parameters: "{#PathDelCmd}"; Flags: logoutput runhidden; Tasks: not addtopath; Check: IsExistingInstallation
9694

97-
Filename: "{app}\{#TrayExe}"; Parameters: "{code:GetPortParam}"; Description: "Start {#B} (runs in the system tray)"; Flags: postinstall waituntilidle; Check: IsUserInstallMode
95+
Filename: "{app}\backrest.exe"; Parameters: "--windows-tray {code:GetPortParam}"; Description: "Start {#B} (runs in the system tray)"; Flags: postinstall waituntilidle; Check: IsUserInstallMode
9896
Filename: "http://localhost:{code:GetPort}/"; Description: "Open {#B} user interface"; Flags: postinstall shellexec
9997

10098
[UninstallRun]
@@ -184,13 +182,13 @@ begin
184182
// Attempt to terminate Backrest gracefully for the current user, wait for a second (since taskkill returns immediately),
185183
// then check and kill forcefully if it's still running.
186184
if IsUserInstallMode then
187-
ExecAndLogOutput(Cmd, '/C "taskkill /FI "USERNAME eq %USERNAME%" /IM "backrest-windows-tray.exe" & ping -n 2 127.0.0.1 >nul & tasklist /FI "USERNAME eq %USERNAME%" | findstr /I /V "setup" | findstr "backrest" && (echo Forcing & taskkill /FI "USERNAME eq %USERNAME%" /IM "backrest-windows-tray.exe" /F & taskkill /FI "USERNAME eq %USERNAME%" /IM "backrest.exe" /F)" ',
185+
ExecAndLogOutput(Cmd, '/C "taskkill /FI "USERNAME eq %USERNAME%" /IM "backrest.exe" & ping -n 2 127.0.0.1 >nul & tasklist /FI "USERNAME eq %USERNAME%" | findstr /I /V "setup" | findstr "backrest" && (echo Forcing & taskkill /FI "USERNAME eq %USERNAME%" /IM "backrest.exe" /F)" ',
188186
'', SW_HIDE, ewWaitUntilTerminated, ResultCode, nil)
189187
// For admin installs stop through the task scheduler. For the SYSTEM or non-current user this is the only way to stop gracefully.
190188
// Ending the scheduled task makes a gracefull attempt, then force kills.
191189
else if IsAdminInstallMode then
192190
begin
193-
ExecAndLogOutput(Cmd, '/C schtasks /End /TN ' + AppName + ' || (taskkill /FI "USERNAME eq %USERNAME%" /IM "backrest-windows-tray.exe" /F & taskkill /FI "USERNAME eq %USERNAME%" /IM "backrest.exe" /F)',
191+
ExecAndLogOutput(Cmd, '/C schtasks /End /TN ' + AppName + ' || (taskkill /FI "USERNAME eq %USERNAME%" /IM "backrest.exe" /F)',
194192
'', SW_HIDE, ewWaitUntilTerminated, ResultCode, nil);
195193
// Remove the task when uninstalling.
196194
if IsUninstaller then

cmd/backrest/backrest.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ var (
4444
commit = "unknown"
4545
)
4646

47-
func main() {
48-
flag.Parse()
47+
func runApp() {
4948
installLoggers()
5049

5150
resticPath, err := resticinstaller.FindOrInstallResticBinary()

cmd/backrest/main_other.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//go:build !windows
2+
3+
package main
4+
5+
import "flag"
6+
7+
func main() {
8+
flag.Parse()
9+
runApp()
10+
}
Lines changed: 9 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,11 @@
44
package main
55

66
import (
7-
"context"
87
"flag"
98
"fmt"
109
"net"
11-
"os"
1210
"os/exec"
13-
"path/filepath"
1411
"runtime"
15-
"syscall"
1612

1713
"github.com/garethgeorge/backrest/internal/env"
1814
"github.com/getlantern/systray"
@@ -24,26 +20,19 @@ import (
2420
//go:embed icon.ico
2521
var icon []byte
2622

23+
var windowsTray = flag.Bool("windows-tray", false, "run the windows tray application")
24+
2725
func main() {
2826
flag.Parse()
29-
backrest, err := findBackrest()
30-
if err != nil {
31-
reportError(err)
32-
return
27+
if *windowsTray {
28+
startTray()
29+
} else {
30+
runApp()
3331
}
32+
}
3433

35-
ctx, cancel := context.WithCancel(context.Background())
36-
37-
cmd := exec.CommandContext(ctx, backrest, os.Args[1:]...)
38-
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
39-
cmd.Env = os.Environ()
40-
cmd.Env = append(cmd.Env, "ENV=production")
41-
42-
if err := cmd.Start(); err != nil {
43-
reportError(err)
44-
cancel()
45-
return
46-
}
34+
func startTray() {
35+
go runApp()
4736

4837
systray.Run(func() {
4938
systray.SetTitle("Backrest Tray")
@@ -85,44 +74,10 @@ func main() {
8574
mQuit.ClickedCh = make(chan struct{})
8675
go func() {
8776
<-mQuit.ClickedCh
88-
cancel()
8977
systray.Quit()
9078
}()
9179
}, func() {
92-
cancel()
9380
})
94-
95-
if err := cmd.Wait(); err != nil {
96-
systray.Quit()
97-
if ctx.Err() != context.Canceled {
98-
reportError(fmt.Errorf("backrest process exited unexpectedly with error: %w", err))
99-
}
100-
return
101-
}
102-
}
103-
104-
func findBackrest() (string, error) {
105-
// Backrest binary must be installed in the same directory as the backresttray binary.
106-
ex, err := os.Executable()
107-
if err != nil {
108-
return "", err
109-
}
110-
dir := filepath.Dir(ex)
111-
112-
wantPath := filepath.Join(dir, backrestBinName())
113-
114-
if stat, err := os.Stat(wantPath); err == nil && !stat.IsDir() {
115-
return wantPath, nil
116-
}
117-
return "", fmt.Errorf("backrest binary not found at %s", wantPath)
118-
}
119-
120-
func backrestBinName() string {
121-
if runtime.GOOS == "windows" {
122-
return "backrest.exe"
123-
} else {
124-
return "backrest"
125-
}
12681
}
12782

12883
func openBrowser(url string) error {

0 commit comments

Comments
 (0)