diff --git a/Makefile b/Makefile index ec1e5231d1..5ff1eaef70 100644 --- a/Makefile +++ b/Makefile @@ -134,6 +134,10 @@ RELEASE_MODE = # proper) on a client that has the run-time system in source form: SOURCE_MODE = +# Set to "--mac-pkg" to create ".pkg"-based installers for Mac OS X, +# instead of a ".dmg" for drag-and-drop installation: +MAC_PKG_MODE = + # Set to "--source --no-setup" to include packages in an installer # (or archive) only in source form: PKG_SOURCE_MODE = @@ -380,7 +384,7 @@ binary-catalog-server: COPY_ARGS = SERVER=$(SERVER) SERVER_PORT=$(SERVER_PORT) SERVER_HOSTS="$(SERVER_HOSTS)" \ PKGS="$(PKGS)" BUILD_STAMP="$(BUILD_STAMP)" \ - RELEASE_MODE=$(RELEASE_MODE) SOURCE_MODE=$(SOURCE_MODE) \ + RELEASE_MODE=$(RELEASE_MODE) SOURCE_MODE=$(SOURCE_MODE) MAC_PKG_MODE=$(MAC_PKG_MODE) \ PKG_SOURCE_MODE="$(PKG_SOURCE_MODE)" INSTALL_NAME="$(INSTALL_NAME)"\ DIST_NAME="$(DIST_NAME)" DIST_BASE=$(DIST_BASE) \ DIST_DIR=$(DIST_DIR) DIST_SUFFIX=$(DIST_SUFFIX) \ @@ -426,7 +430,7 @@ bundle-config: $(RACKET) -l distro-build/set-config $(SET_BUNDLE_CONFIG_q) UPLOAD_q = --readme http://$(SVR_PRT)/$(README) --upload http://$(SVR_PRT)/ --desc "$(DIST_DESC)" -DIST_ARGS_q = $(UPLOAD_q) $(RELEASE_MODE) $(SOURCE_MODE) \ +DIST_ARGS_q = $(UPLOAD_q) $(RELEASE_MODE) $(SOURCE_MODE) $(MAC_PKG_MODE) \ "$(DIST_NAME)" $(DIST_BASE) $(DIST_DIR) "$(DIST_SUFFIX)" \ "$(SIGN_IDENTITY)" diff --git a/pkgs/distro-build/config.rkt b/pkgs/distro-build/config.rkt index 6294d0c505..199e68583a 100644 --- 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 index ed16a93f65..3f4f91bedd 100644 --- a/pkgs/distro-build/doc.txt +++ b/pkgs/distro-build/doc.txt @@ -244,7 +244,7 @@ Site-configuration keywords (where means no spaces, etc.): makefile variable #:source? --- determines the default value for - `#:source-runtime' and `#:source-pkgs' + `#:source-runtime?' and `#:source-pkgs' #:source-runtime? --- 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 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 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 index b08051ef73..eb4a901a9f 100644 --- 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 new file mode 100644 index 0000000000..352f0cc122 --- /dev/null +++ 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 index ce13618520..17fe981be5 100644 --- 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 new file mode 100644 index 0000000000..1d606577d0 Binary files /dev/null and b/pkgs/distro-build/macosx-installer/pkg-bg.png differ diff --git a/pkgs/distro-build/readme.rkt b/pkgs/distro-build/readme.rkt index e7accdb5fe..b8a0358a95 100644 --- 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.}))