commit 5de41c4bc1e9ac8029ad9db819392b2c2f1d5630
parent a80e62d9b150dbc8571310eb9786f157915de69b
Author: Matthew Flatt <mflatt@racket-lang.org>
Date: Sun, 10 Nov 2013 12:17:01 -0700
make installers: support Mac OS X ".pkg" format
The ".pkg"-based installer doesn't provide the option of picking
an installation path, but it can add a path in "/etc/paths.d"
so that users do not have to explicitly set the `PATH` environment
variable.
original commit: 7dd10fc9bd35d8cf10d26c50e4489f9bd6922b53
Diffstat:
7 files changed, 166 insertions(+), 9 deletions(-)
diff --git a/pkgs/distro-build/config.rkt b/pkgs/distro-build/config.rkt
@@ -145,6 +145,7 @@
[(#:source?) (boolean? val)]
[(#:source-runtime?) (boolean? val)]
[(#:source-pkgs?) (boolean? val)]
+ [(#:mac-pkg?) (boolean? val)]
[(#:site-dest) (path-string? val)]
[(#:pdf-doc?) (boolean? val)]
[(#:max-snapshots) (real? val)]
diff --git a/pkgs/distro-build/doc.txt b/pkgs/distro-build/doc.txt
@@ -244,7 +244,7 @@ Site-configuration keywords (where <string*> means no spaces, etc.):
makefile variable
#:source? <boolean> --- determines the default value for
- `#:source-runtime' and `#:source-pkgs'
+ `#:source-runtime?' and `#:source-pkgs'
#:source-runtime? <boolean> --- if true, then create an archive that
contains the run-time system in source form (possibly with built
@@ -258,6 +258,9 @@ Site-configuration keywords (where <string*> means no spaces, etc.):
when the `#:source-runtime?' value is also #t; the default is the
value of `#:source?'
+ #:mac-pkg? --- if true, creates a ".pkg" for Mac OS X (in
+ single-file format) instead of a ".dmg"; the default is #f
+
#:max-snapshots <number> --- number of snapshots to keep, used by
the `snapshot-site' makefile target
diff --git a/pkgs/distro-build/drive-clients.rkt b/pkgs/distro-build/drive-clients.rkt
@@ -277,6 +277,7 @@
(define source? (get-opt c '#:source? #f))
(define source-pkgs? (get-opt c '#:source-pkgs? source?))
(define source-runtime? (get-opt c '#:source-runtime? source?))
+ (define mac-pkg? (get-opt c '#:mac-pkg? #f))
(define install-name (get-opt c '#:install-name (if release?
""
snapshot-install-name)))
@@ -301,6 +302,7 @@
" PKG_SOURCE_MODE=" (if source-pkgs?
(q "--source --no-setup")
(q ""))
+ " MAC_PKG_MODE=" (if mac-pkg? "--mac-pkg" (q ""))
" README=" (q (file-name-from-path readme))))
(define (unix-build c platform host port user server server-port repo clean? pull? readme)
diff --git a/pkgs/distro-build/installer-pkg.rkt b/pkgs/distro-build/installer-pkg.rkt
@@ -0,0 +1,134 @@
+#lang at-exp racket/base
+(require racket/system
+ racket/file
+ racket/format
+ racket/runtime-path
+ ds-store
+ ds-store/alias
+ xml)
+
+(provide installer-pkg)
+
+(define pkgbuild "/usr/bin/pkgbuild")
+(define productbuild "/usr/bin/productbuild")
+
+(define-runtime-path bg-image "macosx-installer/pkg-bg.png")
+
+(define (system*/show . l)
+ (displayln (apply ~a #:separator " " l))
+ (flush-output)
+ (unless (apply system* l)
+ (error "failed")))
+
+(define (gen-install-script install-dest)
+ (~a "#!/bin/sh\n"
+ "echo \"" (regexp-replace* #rx"\""
+ install-dest
+ "\"'\"'\"")
+ "\"/bin > /etc/paths.d/racket\n"))
+
+(define (make-pkg human-name src-dir pkg-name readme sign-identity)
+ (define install-dest (string-append "/Applications/" human-name))
+ (define id (string-append "org.racket-lang."
+ (regexp-replace* #rx" "
+ human-name
+ "-")))
+
+ (define (make-rel dir-name)
+ (let-values ([(base name dir?) (split-path src-dir)])
+ (build-path base dir-name)))
+
+ (define work-dir (make-rel "work"))
+ (delete-directory/files work-dir #:must-exist? #f)
+ (define scripts-dir (make-rel "scripts"))
+ (delete-directory/files scripts-dir #:must-exist? #f)
+ (define resources-dir (make-rel "resources"))
+ (delete-directory/files resources-dir #:must-exist? #f)
+
+ (printf "Creating ~a\n" scripts-dir)
+ (make-directory* scripts-dir)
+ (define postinstall (build-path scripts-dir "postinstall"))
+ (call-with-output-file*
+ postinstall
+ (lambda (o)
+ (write-string (gen-install-script install-dest) o)))
+ (file-or-directory-permissions postinstall #o770)
+
+ (printf "Creating ~a\n" resources-dir)
+ (make-directory* resources-dir)
+ (copy-file bg-image (build-path resources-dir "background.png"))
+
+ (printf "Copying ~a\n" src-dir)
+ (define dest-dir work-dir)
+ (copy-directory/files src-dir dest-dir
+ #:keep-modify-seconds? #t)
+ (when readme
+ (call-with-output-file*
+ (build-path dest-dir "README.txt")
+ #:exists 'truncate
+ (lambda (o)
+ (display readme o))))
+ (copy-file (build-path dest-dir "README.txt")
+ (build-path resources-dir "README.txt"))
+
+ (apply system*/show
+ pkgbuild
+ (append
+ (list "--root" dest-dir
+ "--install-location" install-dest
+ "--scripts" scripts-dir
+ "--identifier" id
+ "--version" (version))
+ (if (string=? sign-identity "")
+ null
+ (list "--sign" sign-identity))
+ (list (make-rel "racket.pkg"))))
+ (define pkg-xml (make-rel "racket.xml"))
+ (system*/show productbuild
+ "--synthesize"
+ "--package" (make-rel "racket.pkg")
+ pkg-xml)
+ (define synthesized (call-with-input-file*
+ pkg-xml
+ read-xml))
+ (define updated
+ (struct-copy document synthesized
+ [element (let ([e (document-element synthesized)])
+ (struct-copy element e
+ [content
+ (list*
+ (element #f #f
+ 'title
+ null
+ (list (pcdata #f #f human-name)))
+ (element #f #f
+ 'readme
+ (list (attribute #f #f 'file "README.txt"))
+ null)
+ (element #f #f
+ 'background
+ (list (attribute #f #f 'file "background.png")
+ (attribute #f #f 'alignment "topleft")
+ (attribute #f #f 'scaling "none"))
+ null)
+ (element-content e))]))]))
+ (call-with-output-file*
+ pkg-xml
+ #:exists 'truncate
+ (lambda (o)
+ (write-xml updated o)))
+ (system*/show productbuild
+ "--distribution" pkg-xml
+ "--package-path" (make-rel 'same)
+ "--resources" resources-dir
+ "--identifier" id
+ "--version" (version)
+ pkg-name))
+
+(define (installer-pkg human-name base-name dist-suffix readme sign-identity)
+ (define pkg-name (format "bundle/~a-~a~a.pkg"
+ base-name
+ (system-library-subpath #f)
+ dist-suffix))
+ (make-pkg human-name "bundle/racket" pkg-name readme sign-identity)
+ pkg-name)
diff --git a/pkgs/distro-build/installer.rkt b/pkgs/distro-build/installer.rkt
@@ -2,6 +2,7 @@
(require racket/cmdline
"installer-sh.rkt"
"installer-dmg.rkt"
+ "installer-pkg.rkt"
"installer-exe.rkt"
"installer-tgz.rkt"
net/url
@@ -12,6 +13,7 @@
(define release? #f)
(define source? #f)
+(define mac-pkg? #f)
(define upload-to #f)
(define upload-desc "")
(define download-readme #f)
@@ -23,6 +25,8 @@
(set! release? #t)]
[("--source") "Create a source installer"
(set! source? #t)]
+ [("--mac-pkg") "Create a \".pkg\" installer on Mac OS X"
+ (set! mac-pkg? #t)]
[("--upload") url "Upload installer"
(set! upload-to url)]
[("--desc") desc "Description to accompany upload"
@@ -58,7 +62,10 @@
(installer-tgz base-name dir-name dist-suffix readme)
(case (system-type)
[(unix) (installer-sh human-name base-name dir-name release? dist-suffix readme)]
- [(macosx) (installer-dmg human-name base-name dist-suffix readme sign-identity)]
+ [(macosx) (if mac-pkg?
+ (installer-pkg (if release? short-human-name human-name)
+ base-name dist-suffix readme sign-identity)
+ (installer-dmg human-name base-name dist-suffix readme sign-identity))]
[(windows) (installer-exe short-human-name base-name release? dist-suffix readme)])))
(call-with-output-file*
diff --git a/pkgs/distro-build/macosx-installer/pkg-bg.png b/pkgs/distro-build/macosx-installer/pkg-bg.png
Binary files differ.
diff --git a/pkgs/distro-build/readme.rkt b/pkgs/distro-build/readme.rkt
@@ -105,10 +105,20 @@
@~a{The distribution includes any pre-installed packages in source form.}]))
(define (make-macosx-notes config)
- @~a{Install by dragging the enclosing
- @|(hash-ref config '#:dist-name "Racket")| v@(version)
- folder to your Applications folder --- or wherever you like. You can
- move the folder at any time, but do not move applications or other
- files within the folder. If you want to use the Racket command-line
- programs, then (optionally) add the path of the "bin" subdirectory to
- your PATH environment variable.})
+ (if (hash-ref config '#:mac-pkg? #f)
+ @~a{The installation directory is
+ /Applications/@(string-append
+ (hash-ref config '#:dist-name "Racket")
+ (if (hash-ref config '#:release? #f)
+ ""
+ (string-append " v" (version))))
+ The installer also adjusts "/etc/paths.d/racket" to point to that
+ directory's "bin" directory, which adjusts the default PATH
+ environment variable for all users.}
+ @~a{Install by dragging the enclosing
+ @|(hash-ref config '#:dist-name "Racket")| v@(version)
+ folder to your Applications folder --- or wherever you like. You can
+ move the folder at any time, but do not move applications or other
+ files within the folder. If you want to use the Racket command-line
+ programs, then (optionally) add the path of the "bin" subdirectory to
+ your PATH environment variable.}))