(module bundle-dist racket/base (require racket/file (only-in racket/base lambda) racket/path racket/system file/zip file/tar) (provide bundle-put-file-extension+style+filters bundle-directory) (define (bundle-file-suffix) (case (system-type) [(macosx) "dmg"] [(windows) "zip"] [(unix) "tgz"])) (define (bundle-put-file-extension+style+filters) (values (bundle-file-suffix) null (case (system-type) [(windows) '(("Zip file" "*.zip"))] [(macosx) '(("Disk image" "*.dmg"))] [(unix) '(("Gzipped tar file" "*.tgz"))]))) (define (add-suffix name suffix) (if (filename-extension name) name (path-replace-suffix name (string->bytes/utf-8 (string-append "." suffix))))) (define (with-prepared-directory dir for-exe? k) ;; If `dir' contains multiple files, create a new ;; directory that contains a copy of `dir' (if (and for-exe? (= 1 (length (directory-list dir)))) (k dir) (let ([temp-dir (make-temporary-file "bundle-tmp-~a" 'directory)]) (dynamic-wind void (lambda () (let ([dest (let-values ([(base name dir?) (split-path dir)]) (build-path temp-dir name))]) (make-directory dest) (let loop ([src dir][dest dest]) (for-each (lambda (f) (let ([src (build-path src f)] [dest (build-path dest f)]) (cond [(directory-exists? src) (make-directory dest) (loop src dest)] [(file-exists? src) (copy-file src dest) (file-or-directory-modify-seconds dest (file-or-directory-modify-seconds src))]))) (directory-list src)))) (k temp-dir)) (lambda () (delete-directory/files temp-dir)))))) (define bundle-directory (lambda (target dir [for-exe? #f]) (let ([target (add-suffix target (bundle-file-suffix))]) (case (system-type) [(macosx) (with-prepared-directory dir for-exe? (lambda (dir) (let* ([cout (open-output-bytes)] [cerr (open-output-bytes)] [cin (open-input-bytes #"")] [p (process*/ports cout cin cerr "/usr/bin/hdiutil" "create" "-format" "UDZO" "-imagekey" "zlib-level=9" "-mode" "555" "-volname" (path->string (path-replace-suffix (file-name-from-path target) #"")) "-srcfolder" (path->string (cleanse-path (path->complete-path dir))) (path->string (cleanse-path (path->complete-path target))))]) ((list-ref p 4) 'wait) (unless (eq? ((list-ref p 4) 'status) 'done-ok) (error 'bundle-directory "error bundling: ~a" (regexp-replace #rx"[\r\n]*$" (get-output-string cerr) ""))))))] [(windows unix) (let-values ([(base name dir?) (split-path (path->complete-path dir))]) (parameterize ([current-directory base]) ((if (eq? 'unix (system-type)) tar-gzip zip) target name)))] [else (error 'bundle-directory "don't know how")])))))