Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ strings. Only declare languages the application itself already ships.
- `linux-icon` — an optional project-relative `.png` file installed as the desktop icon (`/usr/share/pixmaps`, referenced by the generated `.desktop` entry) and used as the AppImage top-level icon. AppImage packaging fails closed without it; deb and rpm warn and install without a desktop icon when the key is omitted.
- `linux-formats` — an optional subset of `("deb" "rpm" "appimage")` selecting which native Linux installer formats `raco rivet release` builds. The default builds all three; the signed tar.gz update payload is always produced regardless.
- `macos-resource-files` — a list of unique project-relative files copied verbatim into the macOS bundle's `Contents/Resources` root before signing. The motivating consumer is `InternetAccessPolicy.plist`: Little Snitch-class firewalls read it from the Resources root and surface its per-host purpose and deny consequences to the user. Names collide fail closed against rivet-managed bundle files (the packaged icon).
- `dmg-background` — an optional project-relative `.png` used as the DMG window background. Declaring it switches `raco rivet release` to the branded drag-to-install layout: the volume carries an `/Applications` symlink and the DMG window gets a fixed 660x400 geometry with both icons placed. Render the PNG at 1320x800 (2x) so it stays sharp on Retina displays; Finder scales it to the window. Without the key the DMG stays a plain single-folder image.
- `dmg-background` — an optional project-relative `.png` used as the DMG window background. Declaring it switches `raco rivet release` to the branded drag-to-install layout: the volume carries an `/Applications` symlink and the DMG window gets a fixed 660x400 geometry with both icons placed. Render the PNG at 1320x800 (2x of the window) so it stays sharp on Retina displays; the aspect ratio must match the window, and the packager downsamples the staged copy to 660x400 because Finder draws the backdrop at native pixel size without scaling it (anything else crops the layout). Keep the bottom ~28pt of the artwork clear (the window bounds include the title bar) and leave the icon-label spans free. Without the key the DMG stays a plain single-folder image.
- `windows-license` — an optional project-relative `.rtf` file shown on the MSI wizard's license page. Without the key, the release pipeline renders the repository `LICENSE` text (or `LICENSE.txt`/`COPYING`) into an RTF automatically; a project with neither ships a neutral notice pointing at the license that installs with the application.
- `windows-installer-bitmaps` — an optional hash with `banner` and `dialog` values naming project-relative `.bmp` files for the MSI wizard (493x58 and 493x312 respectively). Unset values keep the wizard's built-in artwork.

Expand Down
52 changes: 48 additions & 4 deletions rivet-cli/installer.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,10 @@
(run! 'create-installer! xcrun "stapler" "staple" (path->string output)))
output)

;; Branded DMG layout constants. The window geometry matches the generated
;; background artwork aspect ratio (products render 1320x800 PNGs for the
;; 660x400 window), and both icons sit on the horizontal midline.
;; Branded DMG layout constants. The window geometry defines the staged
;; background's point size (products may author 2x artwork for sharpness;
;; it is downsampled before staging), and both icons sit on the horizontal
;; midline.
(define dmg-window-origin-x 200)
(define dmg-window-origin-y 120)
(define dmg-window-width 660)
Expand Down Expand Up @@ -379,6 +380,25 @@
(when (file-exists? path) (delete-file path))
(when (directory-exists? path) (delete-directory/files path)))

;; `sips -g` answers one " pixelWidth: 1320" style line per requested
;; property; the dimensions decide whether the staged backdrop needs
;; resampling and verify the result afterwards.
(define (raster-pixel-size path sips)
(define output
(with-output-to-string
(lambda ()
(run! 'create-installer! sips
"-g" "pixelWidth" "-g" "pixelHeight"
(path->string path)))))
(define width (regexp-match #px"pixelWidth:\\s*([0-9]+)" output))
(define height (regexp-match #px"pixelHeight:\\s*([0-9]+)" output))
(unless (and width height)
(error 'create-installer!
"could not read the dmg background pixel size"
"background" path))
(list (string->number (cadr width))
(string->number (cadr height))))

;; Commercial drag-to-install image: stage the volume contents (bundle,
;; /Applications link, hidden background asset), attach a read/write image,
;; let Finder size the window and place both icons, then convert to the
Expand Down Expand Up @@ -415,7 +435,30 @@
(make-file-or-directory-link "/Applications"
(build-path staging "Applications"))
(make-directory* (build-path staging ".background"))
(copy-file background (build-path staging ".background" "background.png"))
(define staged-background (build-path staging ".background" "background.png"))
(copy-file background staged-background)
;; Finder draws the backdrop 1:1 at its native pixel size — it does not
;; scale it to the window, so a 2x artwork rendered only its top-left
;; quarter and the bottom of the layout fell outside the view (issue
;; #322). Stage the raster at the window's point size so what Finder
;; draws matches the window exactly; products keep authoring 2x artwork
;; for sharpness, and the artwork aspect must already match the window
;; geometry (a mismatch resamples distorted rather than hiding layout).
(define sips (find-executable-path "sips"))
(unless sips
(error 'create-installer! "sips is required to stage the dmg background"))
(unless (equal? (raster-pixel-size staged-background sips)
(list dmg-window-width dmg-window-height))
(run! 'create-installer! sips "-z"
(number->string dmg-window-height)
(number->string dmg-window-width)
(path->string staged-background))
(unless (equal? (raster-pixel-size staged-background sips)
(list dmg-window-width dmg-window-height))
(error 'create-installer!
"the staged dmg background did not resample to the window size"
"background" staged-background
"expected" (list dmg-window-width dmg-window-height))))
(delete-optional! rw-image)
(run! 'create-installer! hdiutil "create" "-fs" "HFS+" "-volname" volume-name
"-srcfolder" (path->string staging)
Expand Down Expand Up @@ -507,4 +550,5 @@
ensure-wix-extensions!
text->rtf
dmg-style-applescript
raster-pixel-size
create-macos-installer!))
30 changes: 28 additions & 2 deletions rivet/tests/macos-installer.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@
(dmg-style-applescript "Smoke \"App\"" "Smoke.app")
"quotes in display names must be AppleScript-escaped")

;; ---------------------------------------------------------------------------
;; Staged background normalization (macOS: raster-pixel-size shells to sips)

(module+ test
(when (equal? 'macosx (system-type 'os))
(define sips (find-executable-path "sips"))
(when sips
(define one-by-one-png
(base64-decode
#"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="))
(define probe (make-temporary-file "rivet-dmg-pixel-~a.png"))
(call-with-output-file probe
#:exists 'truncate/replace
(lambda (out) (write-bytes one-by-one-png out)))
(check-equal? (raster-pixel-size probe sips) '(1 1)
"the reader must report the PNG's own pixel size")
(delete-file probe))))

;; ---------------------------------------------------------------------------
;; Live branded DMG build (macOS hosts with Finder automation)

Expand Down Expand Up @@ -93,8 +111,9 @@
(make-file-or-directory-link "Versions/Current/Racket"
(build-path fw "Racket"))

;; A 1x1 PNG is enough for the live run: Finder scales the background to
;; the window bounds.
;; A 1x1 PNG is enough for the live run: the packager resamples whatever
;; it is given to the window's point size before staging (Finder draws
;; the backdrop at native pixel size and never scales it — issue #322).
(define tiny-png
(base64-decode
#"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="))
Expand Down Expand Up @@ -136,6 +155,13 @@
"the Applications shortcut must be a symlink")
(check-true (file-exists? (build-path mnt ".background" "background.png"))
"the background asset must ride in the hidden folder")
;; The staged backdrop must be exactly the window's point size: Finder
;; draws it 1:1 at native pixel size, so anything else crops the layout
;; (issue #322).
(let ([staged (raster-pixel-size (build-path mnt ".background" "background.png")
(find-executable-path "sips"))])
(check-equal? staged '(660 400)
"the staged background must match the window point size"))
(check-true (file-exists? (build-path mnt ".DS_Store"))
"the Finder styling must have written the icon layout")

Expand Down
Loading