powerful but friendly backup program that runs in your tray, powered by restic devins.page/restray
go restic system-tray
2

Configure Feed

Select the types of activity you want to include in your feed.

refactor: improve packaging

intergrav (Jul 12, 2026, 11:22 PM EDT) b9c5598e 37d386a8

+74 -49
+1 -1
.gitignore
··· 5 5 result 6 6 /Restray 7 7 /Restray.exe 8 - restray_windows_*.syso 8 + /cmd/restray/restray_windows_*.syso
+4 -3
flake.nix
··· 31 31 ldflags = ["-s" "-w" "-X" "main.resticBuiltinPath=${pkgs.restic}/bin/restic" "-X" "main.rusticBuiltinPath=${pkgs.rustic}/bin/rustic"]; 32 32 33 33 env = pkgs.lib.optionalAttrs isDarwin { 34 - CGO_CFLAGS = "-mmacosx-version-min=11.0"; 35 - CGO_LDFLAGS = "-mmacosx-version-min=11.0"; 34 + CGO_CFLAGS = "-mmacosx-version-min=12.0"; 35 + CGO_LDFLAGS = "-mmacosx-version-min=12.0"; 36 + MACOSX_DEPLOYMENT_TARGET = "12.0"; 36 37 }; 37 38 38 39 nativeBuildInputs = [pkgs.installShellFiles]; ··· 50 51 '' 51 52 else '' 52 53 install -Dm644 packaging/linux/restray.desktop $out/share/applications/restray.desktop 53 - install -Dm644 packaging/linux/restray.png $out/share/icons/hicolor/256x256/apps/restray.png 54 + install -Dm644 packaging/linux/restray.png $out/share/icons/hicolor/1024x1024/apps/restray.png 54 55 substituteInPlace $out/share/applications/restray.desktop \ 55 56 --replace-fail "Exec=restray" "Exec=$out/bin/restray" 56 57 install -Dm644 packaging/linux/restray-user.service $out/lib/systemd/user/restray.service
+2 -2
go.mod
··· 1 - module restray 1 + module tangled.org/devins.page/restray 2 2 3 - go 1.26.3 3 + go 1.25.0 4 4 5 5 require ( 6 6 fyne.io/systray v1.12.2
+65 -41
justfile
··· 7 7 8 8 icons: 9 9 #!/usr/bin/env bash 10 - set -e 10 + set -euo pipefail 11 11 tmp=$(mktemp -d) 12 12 trap 'rm -rf "$tmp"' EXIT 13 13 out="{{pkg}}/icons/generated" ··· 17 17 for sheet in idle busy fail download; do 18 18 src="{{pkg}}/icons/$sheet.png" 19 19 [ -f "$src" ] || continue 20 - dims=$(magick identify -format "%w %h" "$src") 21 - w=${dims% *} 22 - sz=${dims#* } 20 + read -r w sz < <(magick identify -format "%w %h\n" "$src") 23 21 cols=$((w / sz)) 24 22 for ((i=0; i<cols; i++)); do 25 23 x=$((i * sz)) ··· 28 26 magick "$tmp/color.png" -alpha extract -background white -alpha shape "$tmp/white.png" 29 27 magick "$tmp/color.png" -alpha extract -background black -alpha shape "$tmp/black.png" 30 28 for variant in color white black; do 31 - cp "$tmp/$variant.png" "$out/${variant}-${sheet}-${n}.png" 29 + mv "$tmp/$variant.png" "$out/${variant}-${sheet}-${n}.png" 32 30 oxipng -o max -z --strip all -a "$out/${variant}-${sheet}-${n}.png" 33 31 magick "$out/${variant}-${sheet}-${n}.png" -define icon:auto-resize=32,16 "$out/${variant}-${sheet}-${n}.ico" 34 32 done ··· 36 34 done 37 35 cp {{icon}} packaging/linux/restray.png 38 36 magick {{icon}} -define icon:auto-resize=256,128,64,48,32,16 packaging/windows/restray.ico 39 - go run github.com/tc-hib/go-winres@latest simply --icon packaging/windows/restray.ico --out packaging/windows/restray 40 - rm -f packaging/windows/restray_windows_386.syso 41 - sizes="" 37 + go run github.com/tc-hib/go-winres@v0.3.3 simply --arch amd64,arm64 --manifest gui --icon packaging/windows/restray.ico --out packaging/windows/restray 38 + sizes=() 42 39 for size in 16 32 128 256 512; do 43 40 magick {{icon}} -resize ${size}x${size} "$tmp/restray-${size}.png" 44 - sizes="$sizes $tmp/restray-${size}.png" 41 + sizes+=("$tmp/restray-${size}.png") 45 42 done 46 - png2icns packaging/darwin/restray.icns $sizes 43 + png2icns packaging/darwin/restray.icns "${sizes[@]}" 47 44 48 45 build target="" arch="": 49 46 #!/usr/bin/env bash 47 + set -euo pipefail 48 + mkdir -p {{bin}} 50 49 zig_arch() { 51 50 case "$1" in 52 51 amd64) echo "x86_64" ;; ··· 66 65 cc=$(env -u DEVELOPER_DIR /usr/bin/xcrun --sdk macosx --find clang) 67 66 CC="$cc" \ 68 67 SDKROOT="$sdk" \ 69 - MACOSX_DEPLOYMENT_TARGET="11.0" \ 70 - CGO_CFLAGS="-isysroot $sdk -mmacosx-version-min=11.0" \ 71 - CGO_LDFLAGS="-isysroot $sdk -mmacosx-version-min=11.0" \ 68 + MACOSX_DEPLOYMENT_TARGET="12.0" \ 69 + CGO_CFLAGS="-isysroot $sdk -mmacosx-version-min=12.0" \ 70 + CGO_LDFLAGS="-isysroot $sdk -mmacosx-version-min=12.0" \ 72 71 GOOS=darwin GOARCH=$arch \ 73 72 go build -trimpath -ldflags "$ldflags -extld=$cc" -o {{bin}}/{{app}}-{{version}}-darwin-$arch ./{{pkg}} ;; 74 73 linux) 75 74 CGO_ENABLED=1 CC="zig cc -target ${za}-linux-gnu" \ 76 75 GOOS=linux GOARCH=$arch go build -trimpath -ldflags "$ldflags" -o {{bin}}/{{app}}-{{version}}-linux-$arch ./{{pkg}} ;; 77 76 windows) 78 - cp -f packaging/windows/restray_windows_${arch}.syso {{pkg}}/ 2>/dev/null || true 79 - CGO_ENABLED=1 CC="zig cc -target ${za}-windows-gnu" \ 80 - GOOS=windows GOARCH=$arch go build -trimpath -ldflags "$ldflags -H=windowsgui" -o {{bin}}/{{app}}-{{version}}-windows-$arch.exe ./{{pkg}} 81 - rm -f {{pkg}}/restray_windows_${arch}.syso ;; 77 + ( 78 + resource="packaging/windows/restray_windows_${arch}.syso" 79 + copied_resource="{{pkg}}/restray_windows_${arch}.syso" 80 + trap 'rm -f "$copied_resource"' EXIT 81 + cp -f "$resource" "$copied_resource" 82 + CGO_ENABLED=1 CC="zig cc -target ${za}-windows-gnu" \ 83 + GOOS=windows GOARCH=$arch go build -trimpath -ldflags "$ldflags -H=windowsgui" -o {{bin}}/{{app}}-{{version}}-windows-$arch.exe ./{{pkg}} 84 + ) ;; 82 85 esac 83 86 } 84 87 build_os() { 85 88 local os=$1 86 - if [ -n "{{arch}}" ]; then build_one "$os" "{{arch}}" 87 - else build_one "$os" amd64 && build_one "$os" arm64; fi 89 + if [ -n "{{arch}}" ]; then 90 + build_one "$os" "{{arch}}" 91 + else 92 + build_one "$os" amd64 93 + build_one "$os" arm64 94 + fi 88 95 } 89 96 case "{{target}}" in 90 97 darwin|linux|windows) build_os "{{target}}" ;; 91 - all) build_os darwin && build_os linux && build_os windows ;; 98 + all) build_os darwin; build_os linux; build_os windows ;; 92 99 "") build_one "$(go env GOOS)" "$(go env GOARCH)" ;; 93 - *) echo "Unknown target: {{target}}. Use: darwin, linux, windows, all" && exit 1 ;; 100 + *) echo "Unknown target: {{target}}. Use: darwin, linux, windows, all"; exit 1 ;; 94 101 esac 95 102 96 103 package target="" arch="": 97 104 #!/usr/bin/env bash 105 + set -euo pipefail 98 106 package_one() { 99 107 local os=$1 arch=$2 100 - just build "$os" "$arch" && just "_package-$os" "$arch" 108 + just build "$os" "$arch" 109 + just "_package-$os" "$arch" 101 110 } 102 111 package_os() { 103 112 local os=$1 104 - if [ -n "{{arch}}" ]; then package_one "$os" "{{arch}}" 105 - else package_one "$os" amd64 && package_one "$os" arm64; fi 113 + if [ -n "{{arch}}" ]; then 114 + package_one "$os" "{{arch}}" 115 + else 116 + package_one "$os" amd64 117 + package_one "$os" arm64 118 + fi 106 119 } 107 120 case "{{target}}" in 108 121 darwin|windows) package_os "{{target}}" ;; 109 - all) package_os darwin && package_os windows ;; 122 + all) package_os darwin; package_os windows ;; 110 123 "") 111 124 case "$(uname)" in 112 125 Darwin) package_os darwin ;; 113 126 MINGW*|MSYS*) package_os windows ;; 114 - *) echo "No packaging for Linux; use 'just build linux' instead" && exit 1 ;; 127 + *) echo "No packaging for Linux; use 'just build linux' instead"; exit 1 ;; 115 128 esac ;; 116 - *) echo "Unknown target: {{target}}. Use: darwin, windows, all" && exit 1 ;; 129 + *) echo "Unknown target: {{target}}. Use: darwin, windows, all"; exit 1 ;; 117 130 esac 118 131 119 132 _package-darwin arch: 120 133 #!/usr/bin/env bash 121 - set -e 134 + set -euo pipefail 122 135 rm -rf {{dist}}/Restray.app 123 136 mkdir -p {{dist}}/Restray.app/Contents/MacOS {{dist}}/Restray.app/Contents/Resources 137 + trap 'rm -rf {{dist}}/Restray.app' EXIT 124 138 cp {{bin}}/{{app}}-{{version}}-darwin-{{arch}} {{dist}}/Restray.app/Contents/MacOS/Restray 125 139 cp packaging/darwin/Info.plist {{dist}}/Restray.app/Contents/Info.plist 126 140 cp packaging/darwin/restray.icns {{dist}}/Restray.app/Contents/Resources/restray.icns ··· 130 144 just _fetch-rustic-darwin {{arch}} 131 145 cp {{bin}}/rustic-darwin-{{arch}} {{dist}}/Restray.app/Contents/Resources/rustic 132 146 chmod +x {{dist}}/Restray.app/Contents/Resources/rustic 133 - (cd {{dist}} && zip -r {{app}}-{{version}}-darwin-{{arch}}-app.zip Restray.app) 134 - rm -rf {{dist}}/Restray.app 147 + while IFS= read -r file; do 148 + references=$( { otool -l "$file" 2>/dev/null || true; } | grep '/nix/store/' || true) 149 + [ -z "$references" ] || { 150 + echo "$file references the Nix store:" >&2 151 + echo "$references" >&2 152 + exit 1 153 + } 154 + done < <(find {{dist}}/Restray.app/Contents -type f) 155 + /usr/bin/ditto -c -k --sequesterRsrc --keepParent {{dist}}/Restray.app {{dist}}/{{app}}-{{version}}-darwin-{{arch}}-app.zip 135 156 136 157 _fetch-restic-darwin arch: 137 158 #!/usr/bin/env bash 138 - set -e 159 + set -euo pipefail 139 160 out="{{bin}}/restic-darwin-{{arch}}" 140 161 [ -f "$out" ] && exit 0 141 162 mkdir -p {{bin}} 142 163 tmp=$(mktemp -d) 143 164 trap 'rm -rf "$tmp"' EXIT 144 - version=$(curl -fsSL https://api.github.com/repos/restic/restic/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4 | sed 's/^v//') 165 + version=$(curl -fsSL https://api.github.com/repos/restic/restic/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p') 166 + [ -n "$version" ] 145 167 curl -fsSL -o "$tmp/restic.bz2" "https://github.com/restic/restic/releases/download/v${version}/restic_${version}_darwin_{{arch}}.bz2" 146 - bunzip2 -c "$tmp/restic.bz2" > "$out" 147 - chmod +x "$out" 168 + bunzip2 -c "$tmp/restic.bz2" > "$tmp/restic" 169 + chmod +x "$tmp/restic" 170 + mv "$tmp/restic" "$out" 148 171 149 172 _fetch-rustic-darwin arch: 150 173 #!/usr/bin/env bash 151 - set -e 174 + set -euo pipefail 152 175 out="{{bin}}/rustic-darwin-{{arch}}" 153 176 [ -f "$out" ] && exit 0 154 177 mkdir -p {{bin}} 155 178 tmp=$(mktemp -d) 156 179 trap 'rm -rf "$tmp"' EXIT 157 - version=$(curl -fsSL https://api.github.com/repos/rustic-rs/rustic/releases/latest | grep '"tag_name"' | head -1 | cut -d'"' -f4 | sed 's/^v//') 180 + version=$(curl -fsSL https://api.github.com/repos/rustic-rs/rustic/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p') 181 + [ -n "$version" ] 158 182 case "{{arch}}" in 159 183 amd64) target=x86_64-apple-darwin ;; 160 184 arm64) target=aarch64-apple-darwin ;; ··· 162 186 esac 163 187 curl -fsSL -o "$tmp/rustic.tar.gz" "https://github.com/rustic-rs/rustic/releases/download/v${version}/rustic-v${version}-${target}.tar.gz" 164 188 tar -xzf "$tmp/rustic.tar.gz" -C "$tmp" 165 - binary=$(find "$tmp" -type f -name rustic -perm -111 | head -1) 189 + binary=$(find "$tmp" -type f -name rustic -perm -111 -print -quit) 166 190 [ -n "$binary" ] 167 - cp "$binary" "$out" 168 - chmod +x "$out" 191 + chmod +x "$binary" 192 + mv "$binary" "$out" 169 193 170 194 _package-windows arch: 195 + #!/usr/bin/env bash 196 + set -euo pipefail 171 197 mkdir -p {{dist}} 172 - cp {{bin}}/{{app}}-{{version}}-windows-{{arch}}.exe {{bin}}/{{app}}.exe 173 198 makensis -DARCH={{arch}} packaging/windows/installer.nsi 174 - rm {{bin}}/{{app}}.exe 175 199 176 200 run: 177 201 just build && {{bin}}/{{app}}-{{version}}-$(go env GOOS)-$(go env GOARCH)
+1 -1
packaging/darwin/Info.plist
··· 21 21 <key>NSHighResolutionCapable</key> 22 22 <true/> 23 23 <key>LSMinimumSystemVersion</key> 24 - <string>11.0</string> 24 + <string>12.0</string> 25 25 <key>LSUIElement</key> 26 26 <true/> 27 27 </dict>
+1 -1
packaging/windows/installer.nsi
··· 23 23 24 24 Section "Install" 25 25 SetOutPath "$INSTDIR" 26 - File "/oname=Restray.exe" "..\..\bin\restray.exe" 26 + File "/oname=Restray.exe" "..\..\bin\restray-${VERSION}-windows-${ARCH}.exe" 27 27 28 28 CreateDirectory "$SMPROGRAMS\Restray" 29 29 CreateShortcut "$SMPROGRAMS\Restray\Restray.lnk" "$INSTDIR\Restray.exe"
packaging/windows/restray_windows_amd64.syso

This is a binary file and will not be displayed.

packaging/windows/restray_windows_arm64.syso

This is a binary file and will not be displayed.