diff --git a/.gitignore b/.gitignore index 3fb9638..ee15b06 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,6 @@ bin/ dist/ result -Restray -Restray.exe +/Restray +/Restray.exe restray_windows_*.syso diff --git a/config.go b/cmd/restray/config.go similarity index 53% rename from config.go rename to cmd/restray/config.go index f9f6281..4a7cf84 100644 --- a/config.go +++ b/cmd/restray/config.go @@ -3,10 +3,8 @@ package main import ( "bufio" _ "embed" - "fmt" "log" "os" - "os/exec" "path/filepath" "runtime" "strings" @@ -133,29 +131,6 @@ func (prof Profile) displayName() string { return "Profile" } -func needsFullDiskAccess() bool { - if runtime.GOOS != "darwin" { - return false - } - f, err := os.Open("/Library/Application Support/com.apple.TCC/TCC.db") // TODO: is this a good idea or should i be doing something else for FDA detection?? appears to work fine - if err == nil { - f.Close() - } - return os.IsPermission(err) -} - -func openFullDiskAccessSettings() { - exec.Command("open", "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles").Start() -} - -func promptFullDiskAccess() { - out, err := exec.Command("osascript", "-e", - `display dialog "Restray needs Full Disk Access to be able to back up all your files." buttons {"Skip", "Open Settings"} default button "Open Settings" with title "Restray" with icon caution`).Output() - if err == nil && strings.Contains(string(out), "Open Settings") { - openFullDiskAccessSettings() - } -} - func envFilesInsecure(profiles []Profile) bool { if runtime.GOOS == "windows" { return false @@ -250,171 +225,11 @@ func ensureEnvFile(path string) { os.WriteFile(path, []byte(defaultEnvTemplate), 0600) } -func openFile(path string) { - var cmd *exec.Cmd - switch runtime.GOOS { - case "darwin": - cmd = exec.Command("open", path) - case "windows": - cmd = exec.Command("rundll32", "url.dll,FileProtocolHandler", path) - default: - cmd = exec.Command("xdg-open", path) - } - cmd.Start() -} - -func openInEditor(path string) { - if runtime.GOOS == "darwin" { - exec.Command("open", "-t", path).Start() - return - } - openFile(path) -} - -func openConsole(prof Profile, profileCount int, terminal, tailFile string) { - vars, err := parseEnvFile(prof.EnvFile) - if err != nil { - log.Printf("console: failed to read env file: %v", err) - return - } - env := os.Environ() - for k, v := range vars { - env = append(env, k+"="+v) - } - if p, _ := findRestic(); p != "" { - dir := filepath.Dir(p) - for i, e := range env { - if strings.HasPrefix(e, "PATH=") { - env[i] = "PATH=" + dir + string(os.PathListSeparator) + e[5:] - break - } - } - } - - consoleMsg := "Restray: environment loaded in shell. Run \"restic\" for commands." - if profileCount > 1 { - consoleMsg = fmt.Sprintf("Restray: environment for profile \"%s\" loaded in shell. Run \"restic\" for commands.", prof.displayName()) - } - tailMsg := "Restray: tailing log." - - var cmd *exec.Cmd - switch runtime.GOOS { - case "darwin": - script, err := os.CreateTemp("", "restray-shell-*.sh") - if err != nil { - return - } - shell := os.Getenv("SHELL") - if shell == "" { - shell = "/bin/zsh" - } - fmt.Fprintf(script, "#!/bin/sh\n") - for k, v := range vars { - fmt.Fprintf(script, "export %s=%q\n", k, v) - } - if p, _ := findRestic(); p != "" { - fmt.Fprintf(script, "export PATH=%q:\"$PATH\"\n", filepath.Dir(p)) - } - fmt.Fprintf(script, "clear\n") - fmt.Fprintf(script, "rm -f %q\n", script.Name()) - fmt.Fprintf(script, "echo '%s'\n", consoleMsg) - if tailFile != "" { - fmt.Fprintf(script, "echo '%s'\n", tailMsg) - fmt.Fprintf(script, "tail -n +1 -f %q &\n", tailFile) - fmt.Fprintf(script, "TAIL_PID=$!\n") - fmt.Fprintf(script, "trap 'kill $TAIL_PID 2>/dev/null; wait $TAIL_PID 2>/dev/null' INT\n") - fmt.Fprintf(script, "wait $TAIL_PID\n") - } - fmt.Fprintf(script, "cd %q\n", configDir()) - fmt.Fprintf(script, "exec %s -l\n", shell) - script.Close() - os.Chmod(script.Name(), 0700) - cmd = exec.Command("open", "-a", darwinTerminalApp(terminal), script.Name()) - case "windows": - script, err := os.CreateTemp("", "restray-shell-*.bat") - if err != nil { - return - } - fmt.Fprintf(script, "@echo off\r\n") - for k, v := range vars { - fmt.Fprintf(script, "set %s=%s\r\n", k, v) - } - if p, _ := findRestic(); p != "" { - fmt.Fprintf(script, "set PATH=%s;%%PATH%%\r\n", filepath.Dir(p)) - } - fmt.Fprintf(script, "echo %s\r\n", consoleMsg) - if tailFile != "" { - fmt.Fprintf(script, "echo %s\r\n", tailMsg) - fmt.Fprintf(script, "echo.\r\n") - fmt.Fprintf(script, "powershell -Command \"Get-Content -Path '%s' -Wait\"\r\n", tailFile) - } - fmt.Fprintf(script, "cd /d %q\r\n", configDir()) - fmt.Fprintf(script, "cmd /k\r\n") - script.Close() - cmd = exec.Command("cmd", "/c", "start", "", script.Name()) - showConsole(cmd) - default: - shell := os.Getenv("SHELL") - if shell == "" { - shell = "/bin/sh" - } - term := terminal - if term == "" { - term = findTerminal() - } - if term == "" { - log.Print("console: no terminal emulator found") - return - } - var script string - if tailFile != "" { - script = fmt.Sprintf("cd %q; clear; echo '%s'; echo '%s'; tail -n +1 -f %q; exec %s", configDir(), consoleMsg, tailMsg, tailFile, shell) - } else { - script = fmt.Sprintf("cd %q; clear; echo '%s'; exec %s", configDir(), consoleMsg, shell) - } - cmd = exec.Command(term, "-e", shell, "-c", script) - cmd.Env = env - } - cmd.Start() -} - func fileExists(path string) bool { _, err := os.Stat(path) return err == nil } -func darwinTerminalApp(terminal string) string { - t := strings.TrimSuffix(strings.ToLower(terminal), ".app") - switch t { - case "", "terminal": - return "Terminal" - case "iterm", "iterm2": - return "iTerm" - case "alacritty": - return "Alacritty" - case "kitty": - return "kitty" - case "ghostty": - return "Ghostty" - case "wezterm": - return "WezTerm" - default: - return terminal - } -} - -func findTerminal() string { - if t := os.Getenv("TERMINAL"); t != "" { - return t - } - for _, t := range []string{"x-terminal-emulator", "gnome-terminal", "konsole", "xfce4-terminal", "xterm"} { - if p, err := exec.LookPath(t); err == nil { - return p - } - } - return "" -} - func watchConfig(onChange func()) { watcher, err := fsnotify.NewWatcher() if err != nil { diff --git a/cmd/restray/console_darwin.go b/cmd/restray/console_darwin.go new file mode 100644 index 0000000..86a7d12 --- /dev/null +++ b/cmd/restray/console_darwin.go @@ -0,0 +1,64 @@ +//go:build darwin + +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" +) + +func consoleCmd(vars map[string]string, consoleMsg, tailMsg, tailFile, terminal string) *exec.Cmd { + script, err := os.CreateTemp("", "restray-shell-*.sh") + if err != nil { + return nil + } + shell := os.Getenv("SHELL") + if shell == "" { + shell = "/bin/zsh" + } + fmt.Fprintf(script, "#!/bin/sh\n") + for k, v := range vars { + fmt.Fprintf(script, "export %s=%q\n", k, v) + } + if p, _ := findRestic(); p != "" { + fmt.Fprintf(script, "export PATH=%q:\"$PATH\"\n", filepath.Dir(p)) + } + fmt.Fprintf(script, "clear\n") + fmt.Fprintf(script, "rm -f %q\n", script.Name()) + fmt.Fprintf(script, "echo '%s'\n", consoleMsg) + if tailFile != "" { + fmt.Fprintf(script, "echo '%s'\n", tailMsg) + fmt.Fprintf(script, "tail -n +1 -f %q &\n", tailFile) + fmt.Fprintf(script, "TAIL_PID=$!\n") + fmt.Fprintf(script, "trap 'kill $TAIL_PID 2>/dev/null; wait $TAIL_PID 2>/dev/null' INT\n") + fmt.Fprintf(script, "wait $TAIL_PID\n") + } + fmt.Fprintf(script, "cd %q\n", configDir()) + fmt.Fprintf(script, "exec %s -l\n", shell) + script.Close() + os.Chmod(script.Name(), 0700) + return exec.Command("open", "-a", darwinTerminalApp(terminal), script.Name()) +} + +func darwinTerminalApp(terminal string) string { + t := strings.TrimSuffix(strings.ToLower(terminal), ".app") + switch t { + case "", "terminal": + return "Terminal" + case "iterm", "iterm2": + return "iTerm" + case "alacritty": + return "Alacritty" + case "kitty": + return "kitty" + case "ghostty": + return "Ghostty" + case "wezterm": + return "WezTerm" + default: + return terminal + } +} diff --git a/cmd/restray/console_other.go b/cmd/restray/console_other.go new file mode 100644 index 0000000..7e29bd2 --- /dev/null +++ b/cmd/restray/console_other.go @@ -0,0 +1,50 @@ +//go:build !darwin && !windows + +package main + +import ( + "fmt" + "log" + "os" + "os/exec" +) + +func findTerminal() string { + if t := os.Getenv("TERMINAL"); t != "" { + return t + } + for _, t := range []string{"x-terminal-emulator", "kgx", "gnome-terminal", "konsole", "xfce4-terminal", "alacritty", "kitty", "foot", "wezterm", "ghostty", "xterm"} { + if p, err := exec.LookPath(t); err == nil { + return p + } + } + return "" +} + +func consoleCmd(vars map[string]string, consoleMsg, tailMsg, tailFile, terminal string) *exec.Cmd { + shell := os.Getenv("SHELL") + if shell == "" { + shell = "/bin/sh" + } + term := terminal + if term == "" { + term = findTerminal() + } + if term == "" { + log.Print("console: no terminal emulator found") + return nil + } + var script string + if tailFile != "" { + script = fmt.Sprintf("cd %q; clear; echo '%s'; echo '%s'; tail -n +1 -f %q; exec %s", configDir(), consoleMsg, tailMsg, tailFile, shell) + } else { + script = fmt.Sprintf("cd %q; clear; echo '%s'; exec %s", configDir(), consoleMsg, shell) + } + cmd := exec.Command(term, "-e", shell, "-c", script) + env := os.Environ() + for k, v := range vars { + env = append(env, k+"="+v) + } + cmd.Env = env + return cmd +} diff --git a/cmd/restray/console_windows.go b/cmd/restray/console_windows.go new file mode 100644 index 0000000..bc0d2ba --- /dev/null +++ b/cmd/restray/console_windows.go @@ -0,0 +1,36 @@ +//go:build windows + +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" +) + +func consoleCmd(vars map[string]string, consoleMsg, tailMsg, tailFile, _ string) *exec.Cmd { + script, err := os.CreateTemp("", "restray-shell-*.bat") + if err != nil { + return nil + } + fmt.Fprintf(script, "@echo off\r\n") + for k, v := range vars { + fmt.Fprintf(script, "set %s=%s\r\n", k, v) + } + if p, _ := findRestic(); p != "" { + fmt.Fprintf(script, "set PATH=%s;%%PATH%%\r\n", filepath.Dir(p)) + } + fmt.Fprintf(script, "echo %s\r\n", consoleMsg) + if tailFile != "" { + fmt.Fprintf(script, "echo %s\r\n", tailMsg) + fmt.Fprintf(script, "echo.\r\n") + fmt.Fprintf(script, "powershell -Command \"Get-Content -Path '%s' -Wait\"\r\n", tailFile) + } + fmt.Fprintf(script, "cd /d %q\r\n", configDir()) + fmt.Fprintf(script, "cmd /k\r\n") + script.Close() + cmd := exec.Command("cmd", "/c", "start", "", script.Name()) + showConsole(cmd) + return cmd +} diff --git a/exec_other.go b/cmd/restray/exec_other.go similarity index 78% rename from exec_other.go rename to cmd/restray/exec_other.go index 56b18d7..fb4c507 100644 --- a/exec_other.go +++ b/cmd/restray/exec_other.go @@ -8,8 +8,7 @@ import ( "syscall" ) -func hideWindow(_ *exec.Cmd) {} -func showConsole(_ *exec.Cmd) {} +func hideWindow(_ *exec.Cmd) {} func interruptProcess(p *os.Process) { p.Signal(os.Interrupt) diff --git a/exec_windows.go b/cmd/restray/exec_windows.go similarity index 100% rename from exec_windows.go rename to cmd/restray/exec_windows.go diff --git a/cmd/restray/fda_darwin.go b/cmd/restray/fda_darwin.go new file mode 100644 index 0000000..19c1808 --- /dev/null +++ b/cmd/restray/fda_darwin.go @@ -0,0 +1,29 @@ +//go:build darwin + +package main + +import ( + "os" + "os/exec" + "strings" +) + +func needsFullDiskAccess() bool { + f, err := os.Open("/Library/Application Support/com.apple.TCC/TCC.db") + if err == nil { + f.Close() + } + return os.IsPermission(err) +} + +func openFullDiskAccessSettings() { + exec.Command("open", "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles").Start() +} + +func promptFullDiskAccess() { + out, err := exec.Command("osascript", "-e", + `display dialog "Restray needs Full Disk Access to be able to back up all your files." buttons {"Skip", "Open Settings"} default button "Open Settings" with title "Restray" with icon caution`).Output() + if err == nil && strings.Contains(string(out), "Open Settings") { + openFullDiskAccessSettings() + } +} diff --git a/cmd/restray/fda_other.go b/cmd/restray/fda_other.go new file mode 100644 index 0000000..eedee63 --- /dev/null +++ b/cmd/restray/fda_other.go @@ -0,0 +1,7 @@ +//go:build !darwin + +package main + +func needsFullDiskAccess() bool { return false } +func openFullDiskAccessSettings() {} +func promptFullDiskAccess() {} diff --git a/icons.go b/cmd/restray/icons.go similarity index 98% rename from icons.go rename to cmd/restray/icons.go index 3c5e81f..7bea8a1 100644 --- a/icons.go +++ b/cmd/restray/icons.go @@ -89,7 +89,7 @@ func setIconAnimated(name string) { var alertIcon []byte -func init() { +func initAlertIcon() { frames := loadIcons(iconVariant() + "-fail-") if len(frames) > 0 { alertIcon = frames[len(frames)-1] diff --git a/icons/busy.png b/cmd/restray/icons/busy.png similarity index 100% rename from icons/busy.png rename to cmd/restray/icons/busy.png diff --git a/icons/download.png b/cmd/restray/icons/download.png similarity index 100% rename from icons/download.png rename to cmd/restray/icons/download.png diff --git a/icons/fail.png b/cmd/restray/icons/fail.png similarity index 100% rename from icons/fail.png rename to cmd/restray/icons/fail.png diff --git a/icons/generated/linux-busy-00.png b/cmd/restray/icons/generated/linux-busy-00.png similarity index 100% rename from icons/generated/linux-busy-00.png rename to cmd/restray/icons/generated/linux-busy-00.png diff --git a/icons/generated/linux-busy-01.png b/cmd/restray/icons/generated/linux-busy-01.png similarity index 100% rename from icons/generated/linux-busy-01.png rename to cmd/restray/icons/generated/linux-busy-01.png diff --git a/icons/generated/linux-busy-02.png b/cmd/restray/icons/generated/linux-busy-02.png similarity index 100% rename from icons/generated/linux-busy-02.png rename to cmd/restray/icons/generated/linux-busy-02.png diff --git a/icons/generated/linux-busy-03.png b/cmd/restray/icons/generated/linux-busy-03.png similarity index 100% rename from icons/generated/linux-busy-03.png rename to cmd/restray/icons/generated/linux-busy-03.png diff --git a/icons/generated/linux-busy-04.png b/cmd/restray/icons/generated/linux-busy-04.png similarity index 100% rename from icons/generated/linux-busy-04.png rename to cmd/restray/icons/generated/linux-busy-04.png diff --git a/icons/generated/linux-busy-05.png b/cmd/restray/icons/generated/linux-busy-05.png similarity index 100% rename from icons/generated/linux-busy-05.png rename to cmd/restray/icons/generated/linux-busy-05.png diff --git a/icons/generated/linux-busy-06.png b/cmd/restray/icons/generated/linux-busy-06.png similarity index 100% rename from icons/generated/linux-busy-06.png rename to cmd/restray/icons/generated/linux-busy-06.png diff --git a/icons/generated/linux-busy-07.png b/cmd/restray/icons/generated/linux-busy-07.png similarity index 100% rename from icons/generated/linux-busy-07.png rename to cmd/restray/icons/generated/linux-busy-07.png diff --git a/icons/generated/linux-busy-08.png b/cmd/restray/icons/generated/linux-busy-08.png similarity index 100% rename from icons/generated/linux-busy-08.png rename to cmd/restray/icons/generated/linux-busy-08.png diff --git a/icons/generated/linux-busy-09.png b/cmd/restray/icons/generated/linux-busy-09.png similarity index 100% rename from icons/generated/linux-busy-09.png rename to cmd/restray/icons/generated/linux-busy-09.png diff --git a/icons/generated/linux-busy-10.png b/cmd/restray/icons/generated/linux-busy-10.png similarity index 100% rename from icons/generated/linux-busy-10.png rename to cmd/restray/icons/generated/linux-busy-10.png diff --git a/icons/generated/linux-busy-11.png b/cmd/restray/icons/generated/linux-busy-11.png similarity index 100% rename from icons/generated/linux-busy-11.png rename to cmd/restray/icons/generated/linux-busy-11.png diff --git a/icons/generated/linux-busy-12.png b/cmd/restray/icons/generated/linux-busy-12.png similarity index 100% rename from icons/generated/linux-busy-12.png rename to cmd/restray/icons/generated/linux-busy-12.png diff --git a/icons/generated/linux-busy-13.png b/cmd/restray/icons/generated/linux-busy-13.png similarity index 100% rename from icons/generated/linux-busy-13.png rename to cmd/restray/icons/generated/linux-busy-13.png diff --git a/icons/generated/linux-busy-14.png b/cmd/restray/icons/generated/linux-busy-14.png similarity index 100% rename from icons/generated/linux-busy-14.png rename to cmd/restray/icons/generated/linux-busy-14.png diff --git a/icons/generated/linux-busy-15.png b/cmd/restray/icons/generated/linux-busy-15.png similarity index 100% rename from icons/generated/linux-busy-15.png rename to cmd/restray/icons/generated/linux-busy-15.png diff --git a/icons/generated/linux-busy-16.png b/cmd/restray/icons/generated/linux-busy-16.png similarity index 100% rename from icons/generated/linux-busy-16.png rename to cmd/restray/icons/generated/linux-busy-16.png diff --git a/icons/generated/linux-download-00.png b/cmd/restray/icons/generated/linux-download-00.png similarity index 100% rename from icons/generated/linux-download-00.png rename to cmd/restray/icons/generated/linux-download-00.png diff --git a/icons/generated/linux-download-01.png b/cmd/restray/icons/generated/linux-download-01.png similarity index 100% rename from icons/generated/linux-download-01.png rename to cmd/restray/icons/generated/linux-download-01.png diff --git a/icons/generated/linux-download-02.png b/cmd/restray/icons/generated/linux-download-02.png similarity index 100% rename from icons/generated/linux-download-02.png rename to cmd/restray/icons/generated/linux-download-02.png diff --git a/icons/generated/linux-download-03.png b/cmd/restray/icons/generated/linux-download-03.png similarity index 100% rename from icons/generated/linux-download-03.png rename to cmd/restray/icons/generated/linux-download-03.png diff --git a/icons/generated/linux-download-04.png b/cmd/restray/icons/generated/linux-download-04.png similarity index 100% rename from icons/generated/linux-download-04.png rename to cmd/restray/icons/generated/linux-download-04.png diff --git a/icons/generated/linux-download-05.png b/cmd/restray/icons/generated/linux-download-05.png similarity index 100% rename from icons/generated/linux-download-05.png rename to cmd/restray/icons/generated/linux-download-05.png diff --git a/icons/generated/linux-download-06.png b/cmd/restray/icons/generated/linux-download-06.png similarity index 100% rename from icons/generated/linux-download-06.png rename to cmd/restray/icons/generated/linux-download-06.png diff --git a/icons/generated/linux-download-07.png b/cmd/restray/icons/generated/linux-download-07.png similarity index 100% rename from icons/generated/linux-download-07.png rename to cmd/restray/icons/generated/linux-download-07.png diff --git a/icons/generated/linux-download-08.png b/cmd/restray/icons/generated/linux-download-08.png similarity index 100% rename from icons/generated/linux-download-08.png rename to cmd/restray/icons/generated/linux-download-08.png diff --git a/icons/generated/linux-download-09.png b/cmd/restray/icons/generated/linux-download-09.png similarity index 100% rename from icons/generated/linux-download-09.png rename to cmd/restray/icons/generated/linux-download-09.png diff --git a/icons/generated/linux-download-10.png b/cmd/restray/icons/generated/linux-download-10.png similarity index 100% rename from icons/generated/linux-download-10.png rename to cmd/restray/icons/generated/linux-download-10.png diff --git a/icons/generated/linux-download-11.png b/cmd/restray/icons/generated/linux-download-11.png similarity index 100% rename from icons/generated/linux-download-11.png rename to cmd/restray/icons/generated/linux-download-11.png diff --git a/icons/generated/linux-download-12.png b/cmd/restray/icons/generated/linux-download-12.png similarity index 100% rename from icons/generated/linux-download-12.png rename to cmd/restray/icons/generated/linux-download-12.png diff --git a/icons/generated/linux-download-13.png b/cmd/restray/icons/generated/linux-download-13.png similarity index 100% rename from icons/generated/linux-download-13.png rename to cmd/restray/icons/generated/linux-download-13.png diff --git a/icons/generated/linux-download-14.png b/cmd/restray/icons/generated/linux-download-14.png similarity index 100% rename from icons/generated/linux-download-14.png rename to cmd/restray/icons/generated/linux-download-14.png diff --git a/icons/generated/linux-download-15.png b/cmd/restray/icons/generated/linux-download-15.png similarity index 100% rename from icons/generated/linux-download-15.png rename to cmd/restray/icons/generated/linux-download-15.png diff --git a/icons/generated/linux-download-16.png b/cmd/restray/icons/generated/linux-download-16.png similarity index 100% rename from icons/generated/linux-download-16.png rename to cmd/restray/icons/generated/linux-download-16.png diff --git a/icons/generated/linux-download-17.png b/cmd/restray/icons/generated/linux-download-17.png similarity index 100% rename from icons/generated/linux-download-17.png rename to cmd/restray/icons/generated/linux-download-17.png diff --git a/icons/generated/linux-download-18.png b/cmd/restray/icons/generated/linux-download-18.png similarity index 100% rename from icons/generated/linux-download-18.png rename to cmd/restray/icons/generated/linux-download-18.png diff --git a/icons/generated/linux-download-19.png b/cmd/restray/icons/generated/linux-download-19.png similarity index 100% rename from icons/generated/linux-download-19.png rename to cmd/restray/icons/generated/linux-download-19.png diff --git a/icons/generated/linux-download-20.png b/cmd/restray/icons/generated/linux-download-20.png similarity index 100% rename from icons/generated/linux-download-20.png rename to cmd/restray/icons/generated/linux-download-20.png diff --git a/icons/generated/linux-download-21.png b/cmd/restray/icons/generated/linux-download-21.png similarity index 100% rename from icons/generated/linux-download-21.png rename to cmd/restray/icons/generated/linux-download-21.png diff --git a/icons/generated/linux-download-22.png b/cmd/restray/icons/generated/linux-download-22.png similarity index 100% rename from icons/generated/linux-download-22.png rename to cmd/restray/icons/generated/linux-download-22.png diff --git a/icons/generated/linux-download-23.png b/cmd/restray/icons/generated/linux-download-23.png similarity index 100% rename from icons/generated/linux-download-23.png rename to cmd/restray/icons/generated/linux-download-23.png diff --git a/icons/generated/linux-download-24.png b/cmd/restray/icons/generated/linux-download-24.png similarity index 100% rename from icons/generated/linux-download-24.png rename to cmd/restray/icons/generated/linux-download-24.png diff --git a/icons/generated/linux-download-25.png b/cmd/restray/icons/generated/linux-download-25.png similarity index 100% rename from icons/generated/linux-download-25.png rename to cmd/restray/icons/generated/linux-download-25.png diff --git a/icons/generated/linux-download-26.png b/cmd/restray/icons/generated/linux-download-26.png similarity index 100% rename from icons/generated/linux-download-26.png rename to cmd/restray/icons/generated/linux-download-26.png diff --git a/icons/generated/linux-download-27.png b/cmd/restray/icons/generated/linux-download-27.png similarity index 100% rename from icons/generated/linux-download-27.png rename to cmd/restray/icons/generated/linux-download-27.png diff --git a/icons/generated/linux-download-28.png b/cmd/restray/icons/generated/linux-download-28.png similarity index 100% rename from icons/generated/linux-download-28.png rename to cmd/restray/icons/generated/linux-download-28.png diff --git a/icons/generated/linux-download-29.png b/cmd/restray/icons/generated/linux-download-29.png similarity index 100% rename from icons/generated/linux-download-29.png rename to cmd/restray/icons/generated/linux-download-29.png diff --git a/icons/generated/linux-download-30.png b/cmd/restray/icons/generated/linux-download-30.png similarity index 100% rename from icons/generated/linux-download-30.png rename to cmd/restray/icons/generated/linux-download-30.png diff --git a/icons/generated/linux-download-31.png b/cmd/restray/icons/generated/linux-download-31.png similarity index 100% rename from icons/generated/linux-download-31.png rename to cmd/restray/icons/generated/linux-download-31.png diff --git a/icons/generated/linux-fail-00.png b/cmd/restray/icons/generated/linux-fail-00.png similarity index 100% rename from icons/generated/linux-fail-00.png rename to cmd/restray/icons/generated/linux-fail-00.png diff --git a/icons/generated/linux-fail-01.png b/cmd/restray/icons/generated/linux-fail-01.png similarity index 100% rename from icons/generated/linux-fail-01.png rename to cmd/restray/icons/generated/linux-fail-01.png diff --git a/icons/generated/linux-fail-02.png b/cmd/restray/icons/generated/linux-fail-02.png similarity index 100% rename from icons/generated/linux-fail-02.png rename to cmd/restray/icons/generated/linux-fail-02.png diff --git a/icons/generated/linux-fail-03.png b/cmd/restray/icons/generated/linux-fail-03.png similarity index 100% rename from icons/generated/linux-fail-03.png rename to cmd/restray/icons/generated/linux-fail-03.png diff --git a/icons/generated/linux-fail-04.png b/cmd/restray/icons/generated/linux-fail-04.png similarity index 100% rename from icons/generated/linux-fail-04.png rename to cmd/restray/icons/generated/linux-fail-04.png diff --git a/icons/generated/linux-fail-05.png b/cmd/restray/icons/generated/linux-fail-05.png similarity index 100% rename from icons/generated/linux-fail-05.png rename to cmd/restray/icons/generated/linux-fail-05.png diff --git a/icons/generated/linux-fail-06.png b/cmd/restray/icons/generated/linux-fail-06.png similarity index 100% rename from icons/generated/linux-fail-06.png rename to cmd/restray/icons/generated/linux-fail-06.png diff --git a/icons/generated/linux-fail-07.png b/cmd/restray/icons/generated/linux-fail-07.png similarity index 100% rename from icons/generated/linux-fail-07.png rename to cmd/restray/icons/generated/linux-fail-07.png diff --git a/icons/generated/linux-fail-08.png b/cmd/restray/icons/generated/linux-fail-08.png similarity index 100% rename from icons/generated/linux-fail-08.png rename to cmd/restray/icons/generated/linux-fail-08.png diff --git a/icons/generated/linux-fail-09.png b/cmd/restray/icons/generated/linux-fail-09.png similarity index 100% rename from icons/generated/linux-fail-09.png rename to cmd/restray/icons/generated/linux-fail-09.png diff --git a/icons/generated/linux-fail-10.png b/cmd/restray/icons/generated/linux-fail-10.png similarity index 100% rename from icons/generated/linux-fail-10.png rename to cmd/restray/icons/generated/linux-fail-10.png diff --git a/icons/generated/linux-fail-11.png b/cmd/restray/icons/generated/linux-fail-11.png similarity index 100% rename from icons/generated/linux-fail-11.png rename to cmd/restray/icons/generated/linux-fail-11.png diff --git a/icons/generated/linux-fail-12.png b/cmd/restray/icons/generated/linux-fail-12.png similarity index 100% rename from icons/generated/linux-fail-12.png rename to cmd/restray/icons/generated/linux-fail-12.png diff --git a/icons/generated/linux-fail-13.png b/cmd/restray/icons/generated/linux-fail-13.png similarity index 100% rename from icons/generated/linux-fail-13.png rename to cmd/restray/icons/generated/linux-fail-13.png diff --git a/icons/generated/linux-fail-14.png b/cmd/restray/icons/generated/linux-fail-14.png similarity index 100% rename from icons/generated/linux-fail-14.png rename to cmd/restray/icons/generated/linux-fail-14.png diff --git a/icons/generated/linux-idle-00.png b/cmd/restray/icons/generated/linux-idle-00.png similarity index 100% rename from icons/generated/linux-idle-00.png rename to cmd/restray/icons/generated/linux-idle-00.png diff --git a/icons/generated/linux-idle-01.png b/cmd/restray/icons/generated/linux-idle-01.png similarity index 100% rename from icons/generated/linux-idle-01.png rename to cmd/restray/icons/generated/linux-idle-01.png diff --git a/icons/generated/linux-idle-02.png b/cmd/restray/icons/generated/linux-idle-02.png similarity index 100% rename from icons/generated/linux-idle-02.png rename to cmd/restray/icons/generated/linux-idle-02.png diff --git a/icons/generated/linux-idle-03.png b/cmd/restray/icons/generated/linux-idle-03.png similarity index 100% rename from icons/generated/linux-idle-03.png rename to cmd/restray/icons/generated/linux-idle-03.png diff --git a/icons/generated/linux-idle-04.png b/cmd/restray/icons/generated/linux-idle-04.png similarity index 100% rename from icons/generated/linux-idle-04.png rename to cmd/restray/icons/generated/linux-idle-04.png diff --git a/icons/generated/linux-idle-05.png b/cmd/restray/icons/generated/linux-idle-05.png similarity index 100% rename from icons/generated/linux-idle-05.png rename to cmd/restray/icons/generated/linux-idle-05.png diff --git a/icons/generated/linux-idle-06.png b/cmd/restray/icons/generated/linux-idle-06.png similarity index 100% rename from icons/generated/linux-idle-06.png rename to cmd/restray/icons/generated/linux-idle-06.png diff --git a/icons/generated/linux-idle-07.png b/cmd/restray/icons/generated/linux-idle-07.png similarity index 100% rename from icons/generated/linux-idle-07.png rename to cmd/restray/icons/generated/linux-idle-07.png diff --git a/icons/generated/linux-idle-08.png b/cmd/restray/icons/generated/linux-idle-08.png similarity index 100% rename from icons/generated/linux-idle-08.png rename to cmd/restray/icons/generated/linux-idle-08.png diff --git a/icons/generated/linux-idle-09.png b/cmd/restray/icons/generated/linux-idle-09.png similarity index 100% rename from icons/generated/linux-idle-09.png rename to cmd/restray/icons/generated/linux-idle-09.png diff --git a/icons/generated/linux-idle-10.png b/cmd/restray/icons/generated/linux-idle-10.png similarity index 100% rename from icons/generated/linux-idle-10.png rename to cmd/restray/icons/generated/linux-idle-10.png diff --git a/icons/generated/linux-idle-11.png b/cmd/restray/icons/generated/linux-idle-11.png similarity index 100% rename from icons/generated/linux-idle-11.png rename to cmd/restray/icons/generated/linux-idle-11.png diff --git a/icons/generated/linux-idle-12.png b/cmd/restray/icons/generated/linux-idle-12.png similarity index 100% rename from icons/generated/linux-idle-12.png rename to cmd/restray/icons/generated/linux-idle-12.png diff --git a/icons/generated/macos-busy-00.png b/cmd/restray/icons/generated/macos-busy-00.png similarity index 100% rename from icons/generated/macos-busy-00.png rename to cmd/restray/icons/generated/macos-busy-00.png diff --git a/icons/generated/macos-busy-01.png b/cmd/restray/icons/generated/macos-busy-01.png similarity index 100% rename from icons/generated/macos-busy-01.png rename to cmd/restray/icons/generated/macos-busy-01.png diff --git a/icons/generated/macos-busy-02.png b/cmd/restray/icons/generated/macos-busy-02.png similarity index 100% rename from icons/generated/macos-busy-02.png rename to cmd/restray/icons/generated/macos-busy-02.png diff --git a/icons/generated/macos-busy-03.png b/cmd/restray/icons/generated/macos-busy-03.png similarity index 100% rename from icons/generated/macos-busy-03.png rename to cmd/restray/icons/generated/macos-busy-03.png diff --git a/icons/generated/macos-busy-04.png b/cmd/restray/icons/generated/macos-busy-04.png similarity index 100% rename from icons/generated/macos-busy-04.png rename to cmd/restray/icons/generated/macos-busy-04.png diff --git a/icons/generated/macos-busy-05.png b/cmd/restray/icons/generated/macos-busy-05.png similarity index 100% rename from icons/generated/macos-busy-05.png rename to cmd/restray/icons/generated/macos-busy-05.png diff --git a/icons/generated/macos-busy-06.png b/cmd/restray/icons/generated/macos-busy-06.png similarity index 100% rename from icons/generated/macos-busy-06.png rename to cmd/restray/icons/generated/macos-busy-06.png diff --git a/icons/generated/macos-busy-07.png b/cmd/restray/icons/generated/macos-busy-07.png similarity index 100% rename from icons/generated/macos-busy-07.png rename to cmd/restray/icons/generated/macos-busy-07.png diff --git a/icons/generated/macos-busy-08.png b/cmd/restray/icons/generated/macos-busy-08.png similarity index 100% rename from icons/generated/macos-busy-08.png rename to cmd/restray/icons/generated/macos-busy-08.png diff --git a/icons/generated/macos-busy-09.png b/cmd/restray/icons/generated/macos-busy-09.png similarity index 100% rename from icons/generated/macos-busy-09.png rename to cmd/restray/icons/generated/macos-busy-09.png diff --git a/icons/generated/macos-busy-10.png b/cmd/restray/icons/generated/macos-busy-10.png similarity index 100% rename from icons/generated/macos-busy-10.png rename to cmd/restray/icons/generated/macos-busy-10.png diff --git a/icons/generated/macos-busy-11.png b/cmd/restray/icons/generated/macos-busy-11.png similarity index 100% rename from icons/generated/macos-busy-11.png rename to cmd/restray/icons/generated/macos-busy-11.png diff --git a/icons/generated/macos-busy-12.png b/cmd/restray/icons/generated/macos-busy-12.png similarity index 100% rename from icons/generated/macos-busy-12.png rename to cmd/restray/icons/generated/macos-busy-12.png diff --git a/icons/generated/macos-busy-13.png b/cmd/restray/icons/generated/macos-busy-13.png similarity index 100% rename from icons/generated/macos-busy-13.png rename to cmd/restray/icons/generated/macos-busy-13.png diff --git a/icons/generated/macos-busy-14.png b/cmd/restray/icons/generated/macos-busy-14.png similarity index 100% rename from icons/generated/macos-busy-14.png rename to cmd/restray/icons/generated/macos-busy-14.png diff --git a/icons/generated/macos-busy-15.png b/cmd/restray/icons/generated/macos-busy-15.png similarity index 100% rename from icons/generated/macos-busy-15.png rename to cmd/restray/icons/generated/macos-busy-15.png diff --git a/icons/generated/macos-busy-16.png b/cmd/restray/icons/generated/macos-busy-16.png similarity index 100% rename from icons/generated/macos-busy-16.png rename to cmd/restray/icons/generated/macos-busy-16.png diff --git a/icons/generated/macos-download-00.png b/cmd/restray/icons/generated/macos-download-00.png similarity index 100% rename from icons/generated/macos-download-00.png rename to cmd/restray/icons/generated/macos-download-00.png diff --git a/icons/generated/macos-download-01.png b/cmd/restray/icons/generated/macos-download-01.png similarity index 100% rename from icons/generated/macos-download-01.png rename to cmd/restray/icons/generated/macos-download-01.png diff --git a/icons/generated/macos-download-02.png b/cmd/restray/icons/generated/macos-download-02.png similarity index 100% rename from icons/generated/macos-download-02.png rename to cmd/restray/icons/generated/macos-download-02.png diff --git a/icons/generated/macos-download-03.png b/cmd/restray/icons/generated/macos-download-03.png similarity index 100% rename from icons/generated/macos-download-03.png rename to cmd/restray/icons/generated/macos-download-03.png diff --git a/icons/generated/macos-download-04.png b/cmd/restray/icons/generated/macos-download-04.png similarity index 100% rename from icons/generated/macos-download-04.png rename to cmd/restray/icons/generated/macos-download-04.png diff --git a/icons/generated/macos-download-05.png b/cmd/restray/icons/generated/macos-download-05.png similarity index 100% rename from icons/generated/macos-download-05.png rename to cmd/restray/icons/generated/macos-download-05.png diff --git a/icons/generated/macos-download-06.png b/cmd/restray/icons/generated/macos-download-06.png similarity index 100% rename from icons/generated/macos-download-06.png rename to cmd/restray/icons/generated/macos-download-06.png diff --git a/icons/generated/macos-download-07.png b/cmd/restray/icons/generated/macos-download-07.png similarity index 100% rename from icons/generated/macos-download-07.png rename to cmd/restray/icons/generated/macos-download-07.png diff --git a/icons/generated/macos-download-08.png b/cmd/restray/icons/generated/macos-download-08.png similarity index 100% rename from icons/generated/macos-download-08.png rename to cmd/restray/icons/generated/macos-download-08.png diff --git a/icons/generated/macos-download-09.png b/cmd/restray/icons/generated/macos-download-09.png similarity index 100% rename from icons/generated/macos-download-09.png rename to cmd/restray/icons/generated/macos-download-09.png diff --git a/icons/generated/macos-download-10.png b/cmd/restray/icons/generated/macos-download-10.png similarity index 100% rename from icons/generated/macos-download-10.png rename to cmd/restray/icons/generated/macos-download-10.png diff --git a/icons/generated/macos-download-11.png b/cmd/restray/icons/generated/macos-download-11.png similarity index 100% rename from icons/generated/macos-download-11.png rename to cmd/restray/icons/generated/macos-download-11.png diff --git a/icons/generated/macos-download-12.png b/cmd/restray/icons/generated/macos-download-12.png similarity index 100% rename from icons/generated/macos-download-12.png rename to cmd/restray/icons/generated/macos-download-12.png diff --git a/icons/generated/macos-download-13.png b/cmd/restray/icons/generated/macos-download-13.png similarity index 100% rename from icons/generated/macos-download-13.png rename to cmd/restray/icons/generated/macos-download-13.png diff --git a/icons/generated/macos-download-14.png b/cmd/restray/icons/generated/macos-download-14.png similarity index 100% rename from icons/generated/macos-download-14.png rename to cmd/restray/icons/generated/macos-download-14.png diff --git a/icons/generated/macos-download-15.png b/cmd/restray/icons/generated/macos-download-15.png similarity index 100% rename from icons/generated/macos-download-15.png rename to cmd/restray/icons/generated/macos-download-15.png diff --git a/icons/generated/macos-download-16.png b/cmd/restray/icons/generated/macos-download-16.png similarity index 100% rename from icons/generated/macos-download-16.png rename to cmd/restray/icons/generated/macos-download-16.png diff --git a/icons/generated/macos-download-17.png b/cmd/restray/icons/generated/macos-download-17.png similarity index 100% rename from icons/generated/macos-download-17.png rename to cmd/restray/icons/generated/macos-download-17.png diff --git a/icons/generated/macos-download-18.png b/cmd/restray/icons/generated/macos-download-18.png similarity index 100% rename from icons/generated/macos-download-18.png rename to cmd/restray/icons/generated/macos-download-18.png diff --git a/icons/generated/macos-download-19.png b/cmd/restray/icons/generated/macos-download-19.png similarity index 100% rename from icons/generated/macos-download-19.png rename to cmd/restray/icons/generated/macos-download-19.png diff --git a/icons/generated/macos-download-20.png b/cmd/restray/icons/generated/macos-download-20.png similarity index 100% rename from icons/generated/macos-download-20.png rename to cmd/restray/icons/generated/macos-download-20.png diff --git a/icons/generated/macos-download-21.png b/cmd/restray/icons/generated/macos-download-21.png similarity index 100% rename from icons/generated/macos-download-21.png rename to cmd/restray/icons/generated/macos-download-21.png diff --git a/icons/generated/macos-download-22.png b/cmd/restray/icons/generated/macos-download-22.png similarity index 100% rename from icons/generated/macos-download-22.png rename to cmd/restray/icons/generated/macos-download-22.png diff --git a/icons/generated/macos-download-23.png b/cmd/restray/icons/generated/macos-download-23.png similarity index 100% rename from icons/generated/macos-download-23.png rename to cmd/restray/icons/generated/macos-download-23.png diff --git a/icons/generated/macos-download-24.png b/cmd/restray/icons/generated/macos-download-24.png similarity index 100% rename from icons/generated/macos-download-24.png rename to cmd/restray/icons/generated/macos-download-24.png diff --git a/icons/generated/macos-download-25.png b/cmd/restray/icons/generated/macos-download-25.png similarity index 100% rename from icons/generated/macos-download-25.png rename to cmd/restray/icons/generated/macos-download-25.png diff --git a/icons/generated/macos-download-26.png b/cmd/restray/icons/generated/macos-download-26.png similarity index 100% rename from icons/generated/macos-download-26.png rename to cmd/restray/icons/generated/macos-download-26.png diff --git a/icons/generated/macos-download-27.png b/cmd/restray/icons/generated/macos-download-27.png similarity index 100% rename from icons/generated/macos-download-27.png rename to cmd/restray/icons/generated/macos-download-27.png diff --git a/icons/generated/macos-download-28.png b/cmd/restray/icons/generated/macos-download-28.png similarity index 100% rename from icons/generated/macos-download-28.png rename to cmd/restray/icons/generated/macos-download-28.png diff --git a/icons/generated/macos-download-29.png b/cmd/restray/icons/generated/macos-download-29.png similarity index 100% rename from icons/generated/macos-download-29.png rename to cmd/restray/icons/generated/macos-download-29.png diff --git a/icons/generated/macos-download-30.png b/cmd/restray/icons/generated/macos-download-30.png similarity index 100% rename from icons/generated/macos-download-30.png rename to cmd/restray/icons/generated/macos-download-30.png diff --git a/icons/generated/macos-download-31.png b/cmd/restray/icons/generated/macos-download-31.png similarity index 100% rename from icons/generated/macos-download-31.png rename to cmd/restray/icons/generated/macos-download-31.png diff --git a/icons/generated/macos-fail-00.png b/cmd/restray/icons/generated/macos-fail-00.png similarity index 100% rename from icons/generated/macos-fail-00.png rename to cmd/restray/icons/generated/macos-fail-00.png diff --git a/icons/generated/macos-fail-01.png b/cmd/restray/icons/generated/macos-fail-01.png similarity index 100% rename from icons/generated/macos-fail-01.png rename to cmd/restray/icons/generated/macos-fail-01.png diff --git a/icons/generated/macos-fail-02.png b/cmd/restray/icons/generated/macos-fail-02.png similarity index 100% rename from icons/generated/macos-fail-02.png rename to cmd/restray/icons/generated/macos-fail-02.png diff --git a/icons/generated/macos-fail-03.png b/cmd/restray/icons/generated/macos-fail-03.png similarity index 100% rename from icons/generated/macos-fail-03.png rename to cmd/restray/icons/generated/macos-fail-03.png diff --git a/icons/generated/macos-fail-04.png b/cmd/restray/icons/generated/macos-fail-04.png similarity index 100% rename from icons/generated/macos-fail-04.png rename to cmd/restray/icons/generated/macos-fail-04.png diff --git a/icons/generated/macos-fail-05.png b/cmd/restray/icons/generated/macos-fail-05.png similarity index 100% rename from icons/generated/macos-fail-05.png rename to cmd/restray/icons/generated/macos-fail-05.png diff --git a/icons/generated/macos-fail-06.png b/cmd/restray/icons/generated/macos-fail-06.png similarity index 100% rename from icons/generated/macos-fail-06.png rename to cmd/restray/icons/generated/macos-fail-06.png diff --git a/icons/generated/macos-fail-07.png b/cmd/restray/icons/generated/macos-fail-07.png similarity index 100% rename from icons/generated/macos-fail-07.png rename to cmd/restray/icons/generated/macos-fail-07.png diff --git a/icons/generated/macos-fail-08.png b/cmd/restray/icons/generated/macos-fail-08.png similarity index 100% rename from icons/generated/macos-fail-08.png rename to cmd/restray/icons/generated/macos-fail-08.png diff --git a/icons/generated/macos-fail-09.png b/cmd/restray/icons/generated/macos-fail-09.png similarity index 100% rename from icons/generated/macos-fail-09.png rename to cmd/restray/icons/generated/macos-fail-09.png diff --git a/icons/generated/macos-fail-10.png b/cmd/restray/icons/generated/macos-fail-10.png similarity index 100% rename from icons/generated/macos-fail-10.png rename to cmd/restray/icons/generated/macos-fail-10.png diff --git a/icons/generated/macos-fail-11.png b/cmd/restray/icons/generated/macos-fail-11.png similarity index 100% rename from icons/generated/macos-fail-11.png rename to cmd/restray/icons/generated/macos-fail-11.png diff --git a/icons/generated/macos-fail-12.png b/cmd/restray/icons/generated/macos-fail-12.png similarity index 100% rename from icons/generated/macos-fail-12.png rename to cmd/restray/icons/generated/macos-fail-12.png diff --git a/icons/generated/macos-fail-13.png b/cmd/restray/icons/generated/macos-fail-13.png similarity index 100% rename from icons/generated/macos-fail-13.png rename to cmd/restray/icons/generated/macos-fail-13.png diff --git a/icons/generated/macos-fail-14.png b/cmd/restray/icons/generated/macos-fail-14.png similarity index 100% rename from icons/generated/macos-fail-14.png rename to cmd/restray/icons/generated/macos-fail-14.png diff --git a/icons/generated/macos-idle-00.png b/cmd/restray/icons/generated/macos-idle-00.png similarity index 100% rename from icons/generated/macos-idle-00.png rename to cmd/restray/icons/generated/macos-idle-00.png diff --git a/icons/generated/macos-idle-01.png b/cmd/restray/icons/generated/macos-idle-01.png similarity index 100% rename from icons/generated/macos-idle-01.png rename to cmd/restray/icons/generated/macos-idle-01.png diff --git a/icons/generated/macos-idle-02.png b/cmd/restray/icons/generated/macos-idle-02.png similarity index 100% rename from icons/generated/macos-idle-02.png rename to cmd/restray/icons/generated/macos-idle-02.png diff --git a/icons/generated/macos-idle-03.png b/cmd/restray/icons/generated/macos-idle-03.png similarity index 100% rename from icons/generated/macos-idle-03.png rename to cmd/restray/icons/generated/macos-idle-03.png diff --git a/icons/generated/macos-idle-04.png b/cmd/restray/icons/generated/macos-idle-04.png similarity index 100% rename from icons/generated/macos-idle-04.png rename to cmd/restray/icons/generated/macos-idle-04.png diff --git a/icons/generated/macos-idle-05.png b/cmd/restray/icons/generated/macos-idle-05.png similarity index 100% rename from icons/generated/macos-idle-05.png rename to cmd/restray/icons/generated/macos-idle-05.png diff --git a/icons/generated/macos-idle-06.png b/cmd/restray/icons/generated/macos-idle-06.png similarity index 100% rename from icons/generated/macos-idle-06.png rename to cmd/restray/icons/generated/macos-idle-06.png diff --git a/icons/generated/macos-idle-07.png b/cmd/restray/icons/generated/macos-idle-07.png similarity index 100% rename from icons/generated/macos-idle-07.png rename to cmd/restray/icons/generated/macos-idle-07.png diff --git a/icons/generated/macos-idle-08.png b/cmd/restray/icons/generated/macos-idle-08.png similarity index 100% rename from icons/generated/macos-idle-08.png rename to cmd/restray/icons/generated/macos-idle-08.png diff --git a/icons/generated/macos-idle-09.png b/cmd/restray/icons/generated/macos-idle-09.png similarity index 100% rename from icons/generated/macos-idle-09.png rename to cmd/restray/icons/generated/macos-idle-09.png diff --git a/icons/generated/macos-idle-10.png b/cmd/restray/icons/generated/macos-idle-10.png similarity index 100% rename from icons/generated/macos-idle-10.png rename to cmd/restray/icons/generated/macos-idle-10.png diff --git a/icons/generated/macos-idle-11.png b/cmd/restray/icons/generated/macos-idle-11.png similarity index 100% rename from icons/generated/macos-idle-11.png rename to cmd/restray/icons/generated/macos-idle-11.png diff --git a/icons/generated/macos-idle-12.png b/cmd/restray/icons/generated/macos-idle-12.png similarity index 100% rename from icons/generated/macos-idle-12.png rename to cmd/restray/icons/generated/macos-idle-12.png diff --git a/icons/generated/windows-busy-00.ico b/cmd/restray/icons/generated/windows-busy-00.ico similarity index 100% rename from icons/generated/windows-busy-00.ico rename to cmd/restray/icons/generated/windows-busy-00.ico diff --git a/icons/generated/windows-busy-01.ico b/cmd/restray/icons/generated/windows-busy-01.ico similarity index 100% rename from icons/generated/windows-busy-01.ico rename to cmd/restray/icons/generated/windows-busy-01.ico diff --git a/icons/generated/windows-busy-02.ico b/cmd/restray/icons/generated/windows-busy-02.ico similarity index 100% rename from icons/generated/windows-busy-02.ico rename to cmd/restray/icons/generated/windows-busy-02.ico diff --git a/icons/generated/windows-busy-03.ico b/cmd/restray/icons/generated/windows-busy-03.ico similarity index 100% rename from icons/generated/windows-busy-03.ico rename to cmd/restray/icons/generated/windows-busy-03.ico diff --git a/icons/generated/windows-busy-04.ico b/cmd/restray/icons/generated/windows-busy-04.ico similarity index 100% rename from icons/generated/windows-busy-04.ico rename to cmd/restray/icons/generated/windows-busy-04.ico diff --git a/icons/generated/windows-busy-05.ico b/cmd/restray/icons/generated/windows-busy-05.ico similarity index 100% rename from icons/generated/windows-busy-05.ico rename to cmd/restray/icons/generated/windows-busy-05.ico diff --git a/icons/generated/windows-busy-06.ico b/cmd/restray/icons/generated/windows-busy-06.ico similarity index 100% rename from icons/generated/windows-busy-06.ico rename to cmd/restray/icons/generated/windows-busy-06.ico diff --git a/icons/generated/windows-busy-07.ico b/cmd/restray/icons/generated/windows-busy-07.ico similarity index 100% rename from icons/generated/windows-busy-07.ico rename to cmd/restray/icons/generated/windows-busy-07.ico diff --git a/icons/generated/windows-busy-08.ico b/cmd/restray/icons/generated/windows-busy-08.ico similarity index 100% rename from icons/generated/windows-busy-08.ico rename to cmd/restray/icons/generated/windows-busy-08.ico diff --git a/icons/generated/windows-busy-09.ico b/cmd/restray/icons/generated/windows-busy-09.ico similarity index 100% rename from icons/generated/windows-busy-09.ico rename to cmd/restray/icons/generated/windows-busy-09.ico diff --git a/icons/generated/windows-busy-10.ico b/cmd/restray/icons/generated/windows-busy-10.ico similarity index 100% rename from icons/generated/windows-busy-10.ico rename to cmd/restray/icons/generated/windows-busy-10.ico diff --git a/icons/generated/windows-busy-11.ico b/cmd/restray/icons/generated/windows-busy-11.ico similarity index 100% rename from icons/generated/windows-busy-11.ico rename to cmd/restray/icons/generated/windows-busy-11.ico diff --git a/icons/generated/windows-busy-12.ico b/cmd/restray/icons/generated/windows-busy-12.ico similarity index 100% rename from icons/generated/windows-busy-12.ico rename to cmd/restray/icons/generated/windows-busy-12.ico diff --git a/icons/generated/windows-busy-13.ico b/cmd/restray/icons/generated/windows-busy-13.ico similarity index 100% rename from icons/generated/windows-busy-13.ico rename to cmd/restray/icons/generated/windows-busy-13.ico diff --git a/icons/generated/windows-busy-14.ico b/cmd/restray/icons/generated/windows-busy-14.ico similarity index 100% rename from icons/generated/windows-busy-14.ico rename to cmd/restray/icons/generated/windows-busy-14.ico diff --git a/icons/generated/windows-busy-15.ico b/cmd/restray/icons/generated/windows-busy-15.ico similarity index 100% rename from icons/generated/windows-busy-15.ico rename to cmd/restray/icons/generated/windows-busy-15.ico diff --git a/icons/generated/windows-busy-16.ico b/cmd/restray/icons/generated/windows-busy-16.ico similarity index 100% rename from icons/generated/windows-busy-16.ico rename to cmd/restray/icons/generated/windows-busy-16.ico diff --git a/icons/generated/windows-download-00.ico b/cmd/restray/icons/generated/windows-download-00.ico similarity index 100% rename from icons/generated/windows-download-00.ico rename to cmd/restray/icons/generated/windows-download-00.ico diff --git a/icons/generated/windows-download-01.ico b/cmd/restray/icons/generated/windows-download-01.ico similarity index 100% rename from icons/generated/windows-download-01.ico rename to cmd/restray/icons/generated/windows-download-01.ico diff --git a/icons/generated/windows-download-02.ico b/cmd/restray/icons/generated/windows-download-02.ico similarity index 100% rename from icons/generated/windows-download-02.ico rename to cmd/restray/icons/generated/windows-download-02.ico diff --git a/icons/generated/windows-download-03.ico b/cmd/restray/icons/generated/windows-download-03.ico similarity index 100% rename from icons/generated/windows-download-03.ico rename to cmd/restray/icons/generated/windows-download-03.ico diff --git a/icons/generated/windows-download-04.ico b/cmd/restray/icons/generated/windows-download-04.ico similarity index 100% rename from icons/generated/windows-download-04.ico rename to cmd/restray/icons/generated/windows-download-04.ico diff --git a/icons/generated/windows-download-05.ico b/cmd/restray/icons/generated/windows-download-05.ico similarity index 100% rename from icons/generated/windows-download-05.ico rename to cmd/restray/icons/generated/windows-download-05.ico diff --git a/icons/generated/windows-download-06.ico b/cmd/restray/icons/generated/windows-download-06.ico similarity index 100% rename from icons/generated/windows-download-06.ico rename to cmd/restray/icons/generated/windows-download-06.ico diff --git a/icons/generated/windows-download-07.ico b/cmd/restray/icons/generated/windows-download-07.ico similarity index 100% rename from icons/generated/windows-download-07.ico rename to cmd/restray/icons/generated/windows-download-07.ico diff --git a/icons/generated/windows-download-08.ico b/cmd/restray/icons/generated/windows-download-08.ico similarity index 100% rename from icons/generated/windows-download-08.ico rename to cmd/restray/icons/generated/windows-download-08.ico diff --git a/icons/generated/windows-download-09.ico b/cmd/restray/icons/generated/windows-download-09.ico similarity index 100% rename from icons/generated/windows-download-09.ico rename to cmd/restray/icons/generated/windows-download-09.ico diff --git a/icons/generated/windows-download-10.ico b/cmd/restray/icons/generated/windows-download-10.ico similarity index 100% rename from icons/generated/windows-download-10.ico rename to cmd/restray/icons/generated/windows-download-10.ico diff --git a/icons/generated/windows-download-11.ico b/cmd/restray/icons/generated/windows-download-11.ico similarity index 100% rename from icons/generated/windows-download-11.ico rename to cmd/restray/icons/generated/windows-download-11.ico diff --git a/icons/generated/windows-download-12.ico b/cmd/restray/icons/generated/windows-download-12.ico similarity index 100% rename from icons/generated/windows-download-12.ico rename to cmd/restray/icons/generated/windows-download-12.ico diff --git a/icons/generated/windows-download-13.ico b/cmd/restray/icons/generated/windows-download-13.ico similarity index 100% rename from icons/generated/windows-download-13.ico rename to cmd/restray/icons/generated/windows-download-13.ico diff --git a/icons/generated/windows-download-14.ico b/cmd/restray/icons/generated/windows-download-14.ico similarity index 100% rename from icons/generated/windows-download-14.ico rename to cmd/restray/icons/generated/windows-download-14.ico diff --git a/icons/generated/windows-download-15.ico b/cmd/restray/icons/generated/windows-download-15.ico similarity index 100% rename from icons/generated/windows-download-15.ico rename to cmd/restray/icons/generated/windows-download-15.ico diff --git a/icons/generated/windows-download-16.ico b/cmd/restray/icons/generated/windows-download-16.ico similarity index 100% rename from icons/generated/windows-download-16.ico rename to cmd/restray/icons/generated/windows-download-16.ico diff --git a/icons/generated/windows-download-17.ico b/cmd/restray/icons/generated/windows-download-17.ico similarity index 100% rename from icons/generated/windows-download-17.ico rename to cmd/restray/icons/generated/windows-download-17.ico diff --git a/icons/generated/windows-download-18.ico b/cmd/restray/icons/generated/windows-download-18.ico similarity index 100% rename from icons/generated/windows-download-18.ico rename to cmd/restray/icons/generated/windows-download-18.ico diff --git a/icons/generated/windows-download-19.ico b/cmd/restray/icons/generated/windows-download-19.ico similarity index 100% rename from icons/generated/windows-download-19.ico rename to cmd/restray/icons/generated/windows-download-19.ico diff --git a/icons/generated/windows-download-20.ico b/cmd/restray/icons/generated/windows-download-20.ico similarity index 100% rename from icons/generated/windows-download-20.ico rename to cmd/restray/icons/generated/windows-download-20.ico diff --git a/icons/generated/windows-download-21.ico b/cmd/restray/icons/generated/windows-download-21.ico similarity index 100% rename from icons/generated/windows-download-21.ico rename to cmd/restray/icons/generated/windows-download-21.ico diff --git a/icons/generated/windows-download-22.ico b/cmd/restray/icons/generated/windows-download-22.ico similarity index 100% rename from icons/generated/windows-download-22.ico rename to cmd/restray/icons/generated/windows-download-22.ico diff --git a/icons/generated/windows-download-23.ico b/cmd/restray/icons/generated/windows-download-23.ico similarity index 100% rename from icons/generated/windows-download-23.ico rename to cmd/restray/icons/generated/windows-download-23.ico diff --git a/icons/generated/windows-download-24.ico b/cmd/restray/icons/generated/windows-download-24.ico similarity index 100% rename from icons/generated/windows-download-24.ico rename to cmd/restray/icons/generated/windows-download-24.ico diff --git a/icons/generated/windows-download-25.ico b/cmd/restray/icons/generated/windows-download-25.ico similarity index 100% rename from icons/generated/windows-download-25.ico rename to cmd/restray/icons/generated/windows-download-25.ico diff --git a/icons/generated/windows-download-26.ico b/cmd/restray/icons/generated/windows-download-26.ico similarity index 100% rename from icons/generated/windows-download-26.ico rename to cmd/restray/icons/generated/windows-download-26.ico diff --git a/icons/generated/windows-download-27.ico b/cmd/restray/icons/generated/windows-download-27.ico similarity index 100% rename from icons/generated/windows-download-27.ico rename to cmd/restray/icons/generated/windows-download-27.ico diff --git a/icons/generated/windows-download-28.ico b/cmd/restray/icons/generated/windows-download-28.ico similarity index 100% rename from icons/generated/windows-download-28.ico rename to cmd/restray/icons/generated/windows-download-28.ico diff --git a/icons/generated/windows-download-29.ico b/cmd/restray/icons/generated/windows-download-29.ico similarity index 100% rename from icons/generated/windows-download-29.ico rename to cmd/restray/icons/generated/windows-download-29.ico diff --git a/icons/generated/windows-download-30.ico b/cmd/restray/icons/generated/windows-download-30.ico similarity index 100% rename from icons/generated/windows-download-30.ico rename to cmd/restray/icons/generated/windows-download-30.ico diff --git a/icons/generated/windows-download-31.ico b/cmd/restray/icons/generated/windows-download-31.ico similarity index 100% rename from icons/generated/windows-download-31.ico rename to cmd/restray/icons/generated/windows-download-31.ico diff --git a/icons/generated/windows-fail-00.ico b/cmd/restray/icons/generated/windows-fail-00.ico similarity index 100% rename from icons/generated/windows-fail-00.ico rename to cmd/restray/icons/generated/windows-fail-00.ico diff --git a/icons/generated/windows-fail-01.ico b/cmd/restray/icons/generated/windows-fail-01.ico similarity index 100% rename from icons/generated/windows-fail-01.ico rename to cmd/restray/icons/generated/windows-fail-01.ico diff --git a/icons/generated/windows-fail-02.ico b/cmd/restray/icons/generated/windows-fail-02.ico similarity index 100% rename from icons/generated/windows-fail-02.ico rename to cmd/restray/icons/generated/windows-fail-02.ico diff --git a/icons/generated/windows-fail-03.ico b/cmd/restray/icons/generated/windows-fail-03.ico similarity index 100% rename from icons/generated/windows-fail-03.ico rename to cmd/restray/icons/generated/windows-fail-03.ico diff --git a/icons/generated/windows-fail-04.ico b/cmd/restray/icons/generated/windows-fail-04.ico similarity index 100% rename from icons/generated/windows-fail-04.ico rename to cmd/restray/icons/generated/windows-fail-04.ico diff --git a/icons/generated/windows-fail-05.ico b/cmd/restray/icons/generated/windows-fail-05.ico similarity index 100% rename from icons/generated/windows-fail-05.ico rename to cmd/restray/icons/generated/windows-fail-05.ico diff --git a/icons/generated/windows-fail-06.ico b/cmd/restray/icons/generated/windows-fail-06.ico similarity index 100% rename from icons/generated/windows-fail-06.ico rename to cmd/restray/icons/generated/windows-fail-06.ico diff --git a/icons/generated/windows-fail-07.ico b/cmd/restray/icons/generated/windows-fail-07.ico similarity index 100% rename from icons/generated/windows-fail-07.ico rename to cmd/restray/icons/generated/windows-fail-07.ico diff --git a/icons/generated/windows-fail-08.ico b/cmd/restray/icons/generated/windows-fail-08.ico similarity index 100% rename from icons/generated/windows-fail-08.ico rename to cmd/restray/icons/generated/windows-fail-08.ico diff --git a/icons/generated/windows-fail-09.ico b/cmd/restray/icons/generated/windows-fail-09.ico similarity index 100% rename from icons/generated/windows-fail-09.ico rename to cmd/restray/icons/generated/windows-fail-09.ico diff --git a/icons/generated/windows-fail-10.ico b/cmd/restray/icons/generated/windows-fail-10.ico similarity index 100% rename from icons/generated/windows-fail-10.ico rename to cmd/restray/icons/generated/windows-fail-10.ico diff --git a/icons/generated/windows-fail-11.ico b/cmd/restray/icons/generated/windows-fail-11.ico similarity index 100% rename from icons/generated/windows-fail-11.ico rename to cmd/restray/icons/generated/windows-fail-11.ico diff --git a/icons/generated/windows-fail-12.ico b/cmd/restray/icons/generated/windows-fail-12.ico similarity index 100% rename from icons/generated/windows-fail-12.ico rename to cmd/restray/icons/generated/windows-fail-12.ico diff --git a/icons/generated/windows-fail-13.ico b/cmd/restray/icons/generated/windows-fail-13.ico similarity index 100% rename from icons/generated/windows-fail-13.ico rename to cmd/restray/icons/generated/windows-fail-13.ico diff --git a/icons/generated/windows-fail-14.ico b/cmd/restray/icons/generated/windows-fail-14.ico similarity index 100% rename from icons/generated/windows-fail-14.ico rename to cmd/restray/icons/generated/windows-fail-14.ico diff --git a/icons/generated/windows-idle-00.ico b/cmd/restray/icons/generated/windows-idle-00.ico similarity index 100% rename from icons/generated/windows-idle-00.ico rename to cmd/restray/icons/generated/windows-idle-00.ico diff --git a/icons/generated/windows-idle-01.ico b/cmd/restray/icons/generated/windows-idle-01.ico similarity index 100% rename from icons/generated/windows-idle-01.ico rename to cmd/restray/icons/generated/windows-idle-01.ico diff --git a/icons/generated/windows-idle-02.ico b/cmd/restray/icons/generated/windows-idle-02.ico similarity index 100% rename from icons/generated/windows-idle-02.ico rename to cmd/restray/icons/generated/windows-idle-02.ico diff --git a/icons/generated/windows-idle-03.ico b/cmd/restray/icons/generated/windows-idle-03.ico similarity index 100% rename from icons/generated/windows-idle-03.ico rename to cmd/restray/icons/generated/windows-idle-03.ico diff --git a/icons/generated/windows-idle-04.ico b/cmd/restray/icons/generated/windows-idle-04.ico similarity index 100% rename from icons/generated/windows-idle-04.ico rename to cmd/restray/icons/generated/windows-idle-04.ico diff --git a/icons/generated/windows-idle-05.ico b/cmd/restray/icons/generated/windows-idle-05.ico similarity index 100% rename from icons/generated/windows-idle-05.ico rename to cmd/restray/icons/generated/windows-idle-05.ico diff --git a/icons/generated/windows-idle-06.ico b/cmd/restray/icons/generated/windows-idle-06.ico similarity index 100% rename from icons/generated/windows-idle-06.ico rename to cmd/restray/icons/generated/windows-idle-06.ico diff --git a/icons/generated/windows-idle-07.ico b/cmd/restray/icons/generated/windows-idle-07.ico similarity index 100% rename from icons/generated/windows-idle-07.ico rename to cmd/restray/icons/generated/windows-idle-07.ico diff --git a/icons/generated/windows-idle-08.ico b/cmd/restray/icons/generated/windows-idle-08.ico similarity index 100% rename from icons/generated/windows-idle-08.ico rename to cmd/restray/icons/generated/windows-idle-08.ico diff --git a/icons/generated/windows-idle-09.ico b/cmd/restray/icons/generated/windows-idle-09.ico similarity index 100% rename from icons/generated/windows-idle-09.ico rename to cmd/restray/icons/generated/windows-idle-09.ico diff --git a/icons/generated/windows-idle-10.ico b/cmd/restray/icons/generated/windows-idle-10.ico similarity index 100% rename from icons/generated/windows-idle-10.ico rename to cmd/restray/icons/generated/windows-idle-10.ico diff --git a/icons/generated/windows-idle-11.ico b/cmd/restray/icons/generated/windows-idle-11.ico similarity index 100% rename from icons/generated/windows-idle-11.ico rename to cmd/restray/icons/generated/windows-idle-11.ico diff --git a/icons/generated/windows-idle-12.ico b/cmd/restray/icons/generated/windows-idle-12.ico similarity index 100% rename from icons/generated/windows-idle-12.ico rename to cmd/restray/icons/generated/windows-idle-12.ico diff --git a/icons/idle.png b/cmd/restray/icons/idle.png similarity index 100% rename from icons/idle.png rename to cmd/restray/icons/idle.png diff --git a/main.go b/cmd/restray/main.go similarity index 87% rename from main.go rename to cmd/restray/main.go index e38ac27..1355adb 100644 --- a/main.go +++ b/cmd/restray/main.go @@ -5,6 +5,7 @@ import ( "os" "fyne.io/systray" + "github.com/gen2brain/beeep" ) const version = "0.6.1" @@ -24,7 +25,9 @@ func main() { log.SetFlags(log.Ldate | log.Ltime) } + beeep.AppName = "Restray" log.Printf("Restray v%s", version) + initAlertIcon() systray.Run(onReady, func() {}) } diff --git a/restic_manage_other.go b/cmd/restray/manage_other.go similarity index 100% rename from restic_manage_other.go rename to cmd/restray/manage_other.go diff --git a/restic_manage_windows.go b/cmd/restray/manage_windows.go similarity index 100% rename from restic_manage_windows.go rename to cmd/restray/manage_windows.go diff --git a/cmd/restray/open_darwin.go b/cmd/restray/open_darwin.go new file mode 100644 index 0000000..7da9dd7 --- /dev/null +++ b/cmd/restray/open_darwin.go @@ -0,0 +1,13 @@ +//go:build darwin + +package main + +import "os/exec" + +func openFile(path string) { + exec.Command("open", path).Start() +} + +func openInEditor(path string) { + exec.Command("open", "-t", path).Start() +} diff --git a/cmd/restray/open_other.go b/cmd/restray/open_other.go new file mode 100644 index 0000000..b49a05d --- /dev/null +++ b/cmd/restray/open_other.go @@ -0,0 +1,13 @@ +//go:build !darwin && !windows + +package main + +import "os/exec" + +func openFile(path string) { + exec.Command("xdg-open", path).Start() +} + +func openInEditor(path string) { + openFile(path) +} diff --git a/cmd/restray/open_windows.go b/cmd/restray/open_windows.go new file mode 100644 index 0000000..d1f690b --- /dev/null +++ b/cmd/restray/open_windows.go @@ -0,0 +1,13 @@ +//go:build windows + +package main + +import "os/exec" + +func openFile(path string) { + exec.Command("rundll32", "url.dll,FileProtocolHandler", path).Start() +} + +func openInEditor(path string) { + openFile(path) +} diff --git a/restic.go b/cmd/restray/operations.go similarity index 70% rename from restic.go rename to cmd/restray/operations.go index c06a39c..b849dc0 100644 --- a/restic.go +++ b/cmd/restray/operations.go @@ -2,7 +2,6 @@ package main import ( "bufio" - "context" "encoding/json" "fmt" "io" @@ -19,196 +18,6 @@ import ( "github.com/gen2brain/beeep" ) -// optional restic path baked at build time for Nix and other pkg managers -var resticBuiltinPath string - -var ( - resticOnce sync.Once - resticPath string - resticManaged bool -) - -func findRestic() (path string, managed bool) { - resticOnce.Do(func() { - if p, err := exec.LookPath("restic"); err == nil { - resticPath = p - return - } - if p := findResticFromShell(); p != "" { - resticPath = p - return - } - if resticBuiltinPath != "" { - if _, err := os.Stat(resticBuiltinPath); err == nil { - resticPath = resticBuiltinPath - return - } - } - if p := managedRestic(); p != "" { - resticPath = p - resticManaged = true - } - }) - return resticPath, resticManaged -} - -func findResticFromShell() string { - if runtime.GOOS == "windows" { - return "" - } - shell := os.Getenv("SHELL") - if shell == "" { - if runtime.GOOS == "darwin" { - shell = "/bin/zsh" - } else { - shell = "/bin/sh" - } - } - out, err := exec.Command(shell, "-l", "-c", "which restic").Output() - if err == nil { - if p := strings.TrimSpace(string(out)); p != "" { - if _, err := os.Stat(p); err == nil { - return p - } - } - } - for _, dir := range []string{ - "/opt/homebrew/bin", - "/usr/local/bin", - filepath.Join(os.Getenv("HOME"), ".nix-profile/bin"), - "/run/current-system/sw/bin", - filepath.Join(os.Getenv("HOME"), ".local/bin"), - } { - p := filepath.Join(dir, "restic") - if _, err := os.Stat(p); err == nil { - return p - } - } - return "" -} - -func resticEnv(prof Profile) []string { - env := os.Environ() - vars, err := parseEnvFile(prof.EnvFile) - if err != nil { - return env - } - for k, v := range vars { - env = append(env, k+"="+v) - } - return env -} - -func resticCmd(prof Profile, args ...string) *exec.Cmd { - path, _ := findRestic() - log.Printf("[%s] run: restic %s", prof.displayName(), strings.Join(args, " ")) - cmd := exec.Command(path, args...) - cmd.Env = resticEnv(prof) - hideWindow(cmd) - return cmd -} - -type repoResult struct { - errMsg string - needsInit bool -} - -func repoStatus(prof Profile) repoResult { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - path, _ := findRestic() - cmd := exec.CommandContext(ctx, path, "cat", "config", "--no-lock", "-q") - cmd.Env = resticEnv(prof) - hideWindow(cmd) - out, err := cmd.CombinedOutput() - if err != nil { - if ctx.Err() != nil { - return repoResult{errMsg: "Repository unreachable"} - } - lines := strings.Split(strings.TrimSpace(string(out)), "\n") - msg, code := classifyError(err, lines[len(lines)-1]) - return repoResult{errMsg: msg, needsInit: code == 10} - } - return repoResult{} -} - -type appState struct { - mu sync.Mutex - busyProfiles map[int]*exec.Cmd - onBusyChanged func(bool) - mountCmds map[int]*exec.Cmd - mountStopping map[int]bool - notifications string - failStatus map[int]string -} - -var state = appState{ - busyProfiles: make(map[int]*exec.Cmd), - mountCmds: make(map[int]*exec.Cmd), - mountStopping: make(map[int]bool), - failStatus: make(map[int]string), -} - -func isProfileBusy(idx int) bool { - state.mu.Lock() - defer state.mu.Unlock() - _, ok := state.busyProfiles[idx] - return ok -} - -func isAnyBusy() bool { - state.mu.Lock() - defer state.mu.Unlock() - return len(state.busyProfiles) > 0 -} - -func setProfileBusy(idx int, active bool) { - state.mu.Lock() - applyBusy(idx, active) -} - -func acquireProfile(idx int) bool { - state.mu.Lock() - if _, busy := state.busyProfiles[idx]; busy { - state.mu.Unlock() - return false - } - applyBusy(idx, true) - return true -} - -func applyBusy(idx int, active bool) { - wasBusy := len(state.busyProfiles) > 0 - if active { - state.busyProfiles[idx] = nil - } else { - delete(state.busyProfiles, idx) - } - nowBusy := len(state.busyProfiles) > 0 - if nowBusy && !wasBusy { - setIconAnimated("busy") - } - cb := state.onBusyChanged - state.mu.Unlock() - if cb != nil { - cb(nowBusy) - } -} - -func setProfileBusyCmd(idx int, cmd *exec.Cmd) { - state.mu.Lock() - defer state.mu.Unlock() - state.busyProfiles[idx] = cmd -} - -func cancelProfile(idx int) { - state.mu.Lock() - defer state.mu.Unlock() - if cmd := state.busyProfiles[idx]; cmd != nil && cmd.Process != nil { - interruptProcess(cmd.Process) - } -} - type stderrLogger struct { mu sync.Mutex last string @@ -238,40 +47,6 @@ func streamStderr(pipe io.Reader, mStatus prefixedMenuItem) *stderrLogger { return sl } -func exitCode(err error) int { - if exitErr, ok := err.(*exec.ExitError); ok { - return exitErr.ExitCode() - } - return -1 -} - -func killedBySystem(err error) bool { - return err != nil && exitCode(err) == -1 && strings.Contains(err.Error(), "killed") -} - -func classifyError(err error, lastStderr string) (string, int) { - code := exitCode(err) - if killedBySystem(err) { - return "Process terminated by system", code - } - if code == 12 { - return "Wrong password", code - } - if lastStderr != "" { - var msg struct { - Message string `json:"message"` - } - if json.Unmarshal([]byte(lastStderr), &msg) == nil && msg.Message != "" { - return msg.Message, code - } - return lastStderr, code - } - if err != nil { - return err.Error(), code - } - return "", code -} - func runResticOnce(idx int, prof Profile, mStatus prefixedMenuItem, args ...string) (string, error) { cmd := resticCmd(prof, args...) var stdout strings.Builder @@ -666,10 +441,6 @@ func stopAllMounts() { } } -func init() { - beeep.AppName = "Restray" -} - func notifyMode() string { state.mu.Lock() defer state.mu.Unlock() @@ -690,3 +461,21 @@ func notifySuccess(operation string) { } beeep.Notify(operation+" complete", operation+" completed successfully", "") } + +func openConsole(prof Profile, profileCount int, terminal, tailFile string) { + vars, err := parseEnvFile(prof.EnvFile) + if err != nil { + log.Printf("console: failed to read env file: %v", err) + return + } + + consoleMsg := "Restray: environment loaded in shell. Run \"restic\" for commands." + if profileCount > 1 { + consoleMsg = fmt.Sprintf("Restray: environment for profile \"%s\" loaded in shell. Run \"restic\" for commands.", prof.displayName()) + } + + cmd := consoleCmd(vars, consoleMsg, "Restray: tailing log.", tailFile, terminal) + if cmd != nil { + cmd.Start() + } +} diff --git a/cmd/restray/restic.go b/cmd/restray/restic.go new file mode 100644 index 0000000..992262f --- /dev/null +++ b/cmd/restray/restic.go @@ -0,0 +1,238 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "sync" + "time" +) + +// optional restic path baked at build time for Nix and other pkg managers +var resticBuiltinPath string + +var ( + resticOnce sync.Once + resticPath string + resticManaged bool +) + +func findRestic() (path string, managed bool) { + resticOnce.Do(func() { + if p, err := exec.LookPath("restic"); err == nil { + resticPath = p + return + } + if p := findResticFromShell(); p != "" { + resticPath = p + return + } + if resticBuiltinPath != "" { + if _, err := os.Stat(resticBuiltinPath); err == nil { + resticPath = resticBuiltinPath + return + } + } + if p := managedRestic(); p != "" { + resticPath = p + resticManaged = true + } + }) + return resticPath, resticManaged +} + +func findResticFromShell() string { + if runtime.GOOS == "windows" { + return "" + } + shell := os.Getenv("SHELL") + if shell == "" { + if runtime.GOOS == "darwin" { + shell = "/bin/zsh" + } else { + shell = "/bin/sh" + } + } + out, err := exec.Command(shell, "-l", "-c", "which restic").Output() + if err == nil { + if p := strings.TrimSpace(string(out)); p != "" { + if _, err := os.Stat(p); err == nil { + return p + } + } + } + for _, dir := range []string{ + "/opt/homebrew/bin", + "/usr/local/bin", + filepath.Join(os.Getenv("HOME"), ".nix-profile/bin"), + "/run/current-system/sw/bin", + filepath.Join(os.Getenv("HOME"), ".local/bin"), + } { + p := filepath.Join(dir, "restic") + if _, err := os.Stat(p); err == nil { + return p + } + } + return "" +} + +func resticEnv(prof Profile) []string { + env := os.Environ() + vars, err := parseEnvFile(prof.EnvFile) + if err != nil { + return env + } + for k, v := range vars { + env = append(env, k+"="+v) + } + return env +} + +func resticCmd(prof Profile, args ...string) *exec.Cmd { + path, _ := findRestic() + log.Printf("[%s] run: restic %s", prof.displayName(), strings.Join(args, " ")) + cmd := exec.Command(path, args...) + cmd.Env = resticEnv(prof) + hideWindow(cmd) + return cmd +} + +type repoResult struct { + errMsg string + needsInit bool +} + +func repoStatus(prof Profile) repoResult { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + path, _ := findRestic() + cmd := exec.CommandContext(ctx, path, "cat", "config", "--no-lock", "-q") + cmd.Env = resticEnv(prof) + hideWindow(cmd) + out, err := cmd.CombinedOutput() + if err != nil { + if ctx.Err() != nil { + return repoResult{errMsg: "Repository unreachable"} + } + lines := strings.Split(strings.TrimSpace(string(out)), "\n") + msg, code := classifyError(err, lines[len(lines)-1]) + return repoResult{errMsg: msg, needsInit: code == 10} + } + return repoResult{} +} + +type appState struct { + mu sync.Mutex + busyProfiles map[int]*exec.Cmd + onBusyChanged func(bool) + mountCmds map[int]*exec.Cmd + mountStopping map[int]bool + notifications string + failStatus map[int]string +} + +var state = appState{ + busyProfiles: make(map[int]*exec.Cmd), + mountCmds: make(map[int]*exec.Cmd), + mountStopping: make(map[int]bool), + failStatus: make(map[int]string), +} + +func isProfileBusy(idx int) bool { + state.mu.Lock() + defer state.mu.Unlock() + _, ok := state.busyProfiles[idx] + return ok +} + +func isAnyBusy() bool { + state.mu.Lock() + defer state.mu.Unlock() + return len(state.busyProfiles) > 0 +} + +func setProfileBusy(idx int, active bool) { + state.mu.Lock() + applyBusy(idx, active) +} + +func acquireProfile(idx int) bool { + state.mu.Lock() + if _, busy := state.busyProfiles[idx]; busy { + state.mu.Unlock() + return false + } + applyBusy(idx, true) + return true +} + +func applyBusy(idx int, active bool) { + wasBusy := len(state.busyProfiles) > 0 + if active { + state.busyProfiles[idx] = nil + } else { + delete(state.busyProfiles, idx) + } + nowBusy := len(state.busyProfiles) > 0 + if nowBusy && !wasBusy { + setIconAnimated("busy") + } + cb := state.onBusyChanged + state.mu.Unlock() + if cb != nil { + cb(nowBusy) + } +} + +func setProfileBusyCmd(idx int, cmd *exec.Cmd) { + state.mu.Lock() + defer state.mu.Unlock() + state.busyProfiles[idx] = cmd +} + +func cancelProfile(idx int) { + state.mu.Lock() + defer state.mu.Unlock() + if cmd := state.busyProfiles[idx]; cmd != nil && cmd.Process != nil { + interruptProcess(cmd.Process) + } +} + +func exitCode(err error) int { + if exitErr, ok := err.(*exec.ExitError); ok { + return exitErr.ExitCode() + } + return -1 +} + +func killedBySystem(err error) bool { + return err != nil && exitCode(err) == -1 && strings.Contains(err.Error(), "killed") +} + +func classifyError(err error, lastStderr string) (string, int) { + code := exitCode(err) + if killedBySystem(err) { + return "Process terminated by system", code + } + if code == 12 { + return "Wrong password", code + } + if lastStderr != "" { + var msg struct { + Message string `json:"message"` + } + if json.Unmarshal([]byte(lastStderr), &msg) == nil && msg.Message != "" { + return msg.Message, code + } + return lastStderr, code + } + if err != nil { + return err.Error(), code + } + return "", code +} diff --git a/templates/config.toml b/cmd/restray/templates/config.toml similarity index 100% rename from templates/config.toml rename to cmd/restray/templates/config.toml diff --git a/templates/default.env b/cmd/restray/templates/default.env similarity index 100% rename from templates/default.env rename to cmd/restray/templates/default.env diff --git a/tray.go b/cmd/restray/tray.go similarity index 100% rename from tray.go rename to cmd/restray/tray.go diff --git a/update.go b/cmd/restray/update.go similarity index 100% rename from update.go rename to cmd/restray/update.go diff --git a/flake.nix b/flake.nix index 1ca6851..d81655e 100644 --- a/flake.nix +++ b/flake.nix @@ -20,6 +20,7 @@ version = "0.6.1"; src = ./.; vendorHash = "sha256-iYM2yvcTsYqn1pyB7jrqroYUfZM4ysWZnXKiLRVqkT0="; + subPackages = ["cmd/restray"]; ldflags = ["-X" "main.resticBuiltinPath=${pkgs.restic}/bin/restic"]; diff --git a/justfile b/justfile index a42b228..763be3f 100644 --- a/justfile +++ b/justfile @@ -1,16 +1,19 @@ app := "Restray" -version := "0.6.1" +version := `grep 'const version' cmd/restray/main.go | cut -d'"' -f2` bin := "bin" dist := "dist" +pkg := "cmd/restray" icons: #!/usr/bin/env bash set -e - out="icons/generated" + tmp=$(mktemp -d) + trap 'rm -rf "$tmp"' EXIT + out="{{pkg}}/icons/generated" rm -rf "$out" mkdir -p "$out" for sheet in idle busy fail download; do - src="icons/$sheet.png" + src="{{pkg}}/icons/$sheet.png" [ -f "$src" ] || continue dims=$(magick identify -format "%w %h" "$src") w=${dims% *} @@ -19,13 +22,12 @@ icons: for ((i=0; i/dev/null | sort | tail -1) if [ -n "$last" ]; then @@ -35,11 +37,10 @@ icons: rm -f packaging/windows/restray_windows_386.syso sizes="" for size in 16 32 128 256 512; do - magick "$last" -resize ${size}x${size} "/tmp/restray-${size}.png" - sizes="$sizes /tmp/restray-${size}.png" + magick "$last" -resize ${size}x${size} "$tmp/restray-${size}.png" + sizes="$sizes $tmp/restray-${size}.png" done png2icns packaging/darwin/restray.icns $sizes - rm -f $sizes fi build target="" arch="": @@ -58,15 +59,15 @@ build target="" arch="": darwin) export CGO_CFLAGS="-mmacosx-version-min=11.0" export CGO_LDFLAGS="-mmacosx-version-min=11.0" - GOOS=darwin GOARCH=$arch go build -o {{bin}}/{{app}}-{{version}}-darwin-$arch . ;; + GOOS=darwin GOARCH=$arch go build -o {{bin}}/{{app}}-{{version}}-darwin-$arch ./{{pkg}} ;; linux) CGO_ENABLED=1 CC="zig cc -target ${za}-linux-gnu" \ - GOOS=linux GOARCH=$arch go build -o {{bin}}/{{app}}-{{version}}-linux-$arch . ;; + GOOS=linux GOARCH=$arch go build -o {{bin}}/{{app}}-{{version}}-linux-$arch ./{{pkg}} ;; windows) - cp -f packaging/windows/restray_windows_${arch}.syso . 2>/dev/null || true + cp -f packaging/windows/restray_windows_${arch}.syso {{pkg}}/ 2>/dev/null || true CGO_ENABLED=1 CC="zig cc -target ${za}-windows-gnu" \ - GOOS=windows GOARCH=$arch go build -ldflags -H=windowsgui -o {{bin}}/{{app}}-{{version}}-windows-$arch.exe . - rm -f restray_windows_${arch}.syso ;; + GOOS=windows GOARCH=$arch go build -ldflags -H=windowsgui -o {{bin}}/{{app}}-{{version}}-windows-$arch.exe ./{{pkg}} + rm -f {{pkg}}/restray_windows_${arch}.syso ;; esac } build_os() { @@ -131,21 +132,20 @@ run: just build && {{bin}}/{{app}}-{{version}}-$(go env GOOS)-$(go env GOARCH) lint: - goimports -w . - go vet . - staticcheck . + goimports -w {{pkg}} + go vet ./{{pkg}} + staticcheck ./{{pkg}} bump new: #!/usr/bin/env bash set -euo pipefail [[ "{{new}}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "Usage: just bump X.Y.Z"; exit 1; } - perl -pi -e 's/^version := ".*"/version := "{{new}}"/' justfile - perl -pi -e 's/^const version = ".*"/const version = "{{new}}"/' main.go + perl -pi -e 's/^const version = ".*"/const version = "{{new}}"/' {{pkg}}/main.go perl -pi -e 's/version = ".*"/version = "{{new}}"/' flake.nix perl -pi -e 's/!define VERSION ".*"/!define VERSION "{{new}}"/' packaging/windows/installer.nsi perl -pi -e 's|()[^<]*()|${1}{{new}}${2}| if $prev =~ /CFBundle(Version|ShortVersionString)/; $prev = $_' packaging/darwin/Info.plist echo "Bumped to {{new}}" - grep -n "{{new}}" justfile main.go flake.nix packaging/windows/installer.nsi packaging/darwin/Info.plist + grep -n "{{new}}" {{pkg}}/main.go flake.nix packaging/windows/installer.nsi packaging/darwin/Info.plist clean: rm -rf {{bin}} {{dist}} result