www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit cb01a4af0f1062a21890970410d33f8525491f25
parent eb48ea6e1f5354d6b94fef6a53cf7201c72a85cd
Author: Matthew Flatt <mflatt@racket-lang.org>
Date:   Mon,  1 Jul 2013 06:57:13 -0600

change farm-configuration file to a module

Also, improve connection between installers and farm-configuration
entries, and improve configuration of installer name versus
target-install directory.

original commit: 29b9a22d87a7567a851f28d0381267611ee8a48f

Diffstat:
Mpkgs/distro-build/drive-clients.rkt | 261+++++++++++++------------------------------------------------------------------
Apkgs/distro-build/farm.rkt | 313+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpkgs/distro-build/installer-dmg.rkt | 4++--
Mpkgs/distro-build/installer-exe.rkt | 4++--
Mpkgs/distro-build/installer-sh.rkt | 4++--
Mpkgs/distro-build/installer.rkt | 21++++++++++++++-------
Mpkgs/distro-build/serve-catalog.rkt | 26++++++++++++++++++++++++++
7 files changed, 400 insertions(+), 233 deletions(-)

diff --git a/pkgs/distro-build/drive-clients.rkt b/pkgs/distro-build/drive-clients.rkt @@ -1,245 +1,57 @@ #lang racket/base - -;; Each client is built by running commands via `ssh', where the -;; client's host (and optional port and/or user) indicate the ssh -;; target. Each client machine must be set up with a public-key -;; authenticaion, because a direct `ssh' is expected to work without a -;; password prompt. -;; -;; On the client machine, all work is performed with a git clone at a -;; specified directory that defaults to "build/plt" (Unix, Mac OS X) -;; or "build\\plt" (Windows). -;; -;; If a build fails for a machine, building continues on other -;; machines. Success for a given machine means that its installer -;; ends up in "build/installers" (and failure for a machine means no -;; installer). -;; -;; Machine Requirements -;; -------------------- -;; -;; Each Unix or Mac OS X client needs the following available: -;; -;; * ssh server with public-key authentication -;; * git -;; * gcc, make, etc. -;; -;; Each Windows client needs the following: -;; -;; * git -;; * Microsoft Visual Studio 9.0 (2008), installed in the -;; default folder: -;; C:\Program Files\Microsoft Visual Studio 9.0 (32-bit host) -;; C:\Program Files (x86)\Microsoft Visual Studio 9.0 (64-bit host) -;; * Nullsoft Scriptable Install System (NSIS), installed in the -;; default folder: -;; C:\Program Files\NSIS\makensis.exe -;; or C:\Program Files (x86)\NSIS\makensis.exe -;; or instaled so that `makensis' in in yur PATH. -;; -;; Farm Configuration -;; ------------------- -;; -;; A farm configuration file is `read' to obtain a configuration. The -;; file must have a single S-expression that matches the <config> -;; grammar: -;; -;; <config> = (machine <keyword> <val> ... ...) -;; | (<group-kind> <keyword> <val> ... ... <config> ...) -;; -;; <group-kind> = parallel | sequential -;; -;; Normally, a configuration file start with "(<group-kind> ...)", since -;; the configuration otherwise specifies only one client machine. -;; -;; A `<keyword> <val> ... ...' sequence specifies options as -;; keyword--value pairs. The available options are listed below. The -;; options of a group are propagated to all machines in the group, -;; except at overridden at a machine or nested group. -;; -;; A <group-kind> specifies whether the machines within a group are -;; run sequentially or in parallel. Note that the default`#:max-vm' -;; setting is 1, so a parallel configuration of virtual machines will -;; fail (for some machines) unless `#:max-vm' is increased. -;; -;; Machine/group keywords (where <string*> means no spaces, etc.): -;; -;; #:pkgs (<string*> ...) --- packages to install; defaults to -;; the `pkgs' command-line argument -;; #:server <string*> --- the address of the server from the client; -;; defaults to `server' command-line argument -;; #:dist-name <string> --- the distribution name; defaults to the -;; `dist-name' command-line argument -;; #:dist-dir <string*> --- the distribution's installation directory; -;; defaults to `dist-dir' command-line argument -;; #:dist-suffix <string*> --- a suffix for the installer's name, usually -;; used for an OS variant; defaults to "" -;; #:max-vm <real> --- max number of VMs allowed to run with this -;; machine, counting the machine; defaults to 1 -;; #:port <integer> --- ssh port for the client; defaults to 22 -;; #:user <string*> --- ssh user for the client; defaults to current user -;; #:dir <string> --- defaults to "build/plt" or "build\\plt" -;; #:vbox <string> --- Virtual Box machine name; if provided the -;; virtual machine is started and stopped as needed -;; #:platform <symbol> --- 'windows or 'unix, defaults to 'unix -;; #:configure (<string> ...) --- arguments to `configure' -;; #:bits <integer> --- 32 or 64, affects Visual Studio path -;; #:vc <string*> --- "x86" or "x64" to select the Visual C build mode; -;; default depends on bits -;; #:j <integer> --- parallelism for `make' on Unix and Mac OS X; -;; defaults to 1 -;; #:timeout <number> --- numbers of seconds to wait before declaring -;; failure; defaults to 30 minutes -;; #:repo <string> --- the git repository for Racket; defaults to -;; "http://<server>:9440/.git" -;; #:clean? <boolean> --- override default cleaning mode -;; -;; Machine-only keywords: -;; #:name <string> --- defaults to host -;; #:host <string*> --- defaults to "localhost" - -;; ---------------------------------------- - (require racket/cmdline racket/system racket/port racket/format racket/file - racket/string) + racket/string + (only-in "farm.rkt" + current-mode + farm-config? + farm-config-tag farm-config-options farm-config-content)) + +;; See "farm.rkt" for an overview. ;; ---------------------------------------- (define release? #f) (define default-clean? #f) -(define-values (config-file default-server default-pkgs default-dist-name default-dist-dir) +(define-values (config-file config-mode + default-server default-pkgs + default-dist-name default-dist-base default-dist-dir) (command-line #:once-each [("--release") "Create release-mode installers" (set! release? #t)] [("--clean") "Erase client directories before building" (set! default-clean? #t)] - #:args (config-file server pkgs dist-name dist-dir) - (values config-file server pkgs dist-name dist-dir))) + #:args (config-file config-mode + server pkgs + dist-name dist-base dist-dir) + (values config-file config-mode + server pkgs + dist-name dist-base dist-dir))) -(define config (call-with-input-file* config-file read)) - -;; ---------------------------------------- - -(define (simple-string? s) - (and (string? s) - ;; No spaces, quotes, or other things that could - ;; break a command-line, path, or URL construction: - (regexp-match #rx"^[-a-zA-A0-9.]*$" s))) - -(define (check-group-keyword kw val) - (case kw - [(#:pkgs) (and (list? val) (andmap simple-string? val))] - [(#:dist-name) (string? val)] - [(#:dist-dir) (simple-string? val)] - [(#:dist-suffix) (simple-string? val)] - [(#:max-vm) (real? val)] - [(#:server) (simple-string? val)] - [(#:host) (simple-string? val)] - [(#:user) (simple-string? val)] - [(#:port) (and (exact-integer? val) (<= 1 val 65535))] - [(#:dir) (string? val)] - [(#:vbox) (string? val)] - [(#:platform) (memq val '(unix windows))] - [(#:configure) (and (list? val) (andmap string? val))] - [(#:bits) (or (equal? val 32) (equal? val 64))] - [(#:vc) (or (equal? val "x86") (equal? val "x64"))] - [(#:timeout) (real? val)] - [(#:j) (exact-positive-integer? val)] - [(#:repo) (string? val)] - [(#:clean?) (boolean? val)] - [else #f])) - -(define (check-machine-keyword kw val) - (case kw - [(#:name) (string? val)] - [else (check-group-keyword kw val)])) - -(define (check-config config) - (define (bad-format msg . rest) - (raise-user-error 'drive-clients - "~a" - (apply ~a "bad configuration" - "\n " msg - (if config-file - (~a "\n config file: " - config-file) - "") - rest))) - (unless (list? config) - (bad-format (if config-file - "does not `read' as a list" - "not a list"))) - (let loop ([config config]) - (unless (list? config) - (bad-format "not a list" - (format "\n given: ~e" config))) - (cond - [(and (pair? config) - (or (eq? 'parallel (car config)) - (eq? 'sequential (car config)))) - (let gloop ([group (cdr config)]) - (cond - [(keyword? (car group)) - (unless (pair? (cdr group)) - (bad-format "missing value after group keyword" - (format "\n keyword: ~e" (car group)))) - (unless (check-group-keyword (car group) (cadr group)) - (bad-format "bad value for keyword in group" - (format "\n keyword: ~e\n value: ~e" - (car group) - (cadr group)))) - (gloop (cddr group))] - [else (for-each loop group)]))] - [(and (pair? config) - (eq? 'machine (car config))) - (let loop ([client (cdr config)]) - (cond - [(null? client) (void)] - [(keyword? (car client)) - (unless (pair? (cdr client)) - (bad-format "machine spec missing value after keyword" - (format "\n keyword: ~e" (car client)))) - (unless (check-machine-keyword (car client) (cadr client)) - (bad-format "bad value for keyword in machine spec" - (format "\n keyword: ~e\n value: ~e" - (car client) - (cadr client)))) - (loop (cddr client))] - [else - (bad-format "bad machine spec; expected a keyword" - (format "\n found: ~e" (car client)))]))] - [else - (bad-format "bad format (does not start with 'machine, 'parallel, or 'sequential)" - (format "\n found: ~e" config))]))) +(define config (parameterize ([current-mode config-mode]) + (dynamic-require (path->complete-path config-file) 'farm-config))) -(check-config config) +(unless (farm-config? config) + (error 'drive-clients + "configuration module did not provide a farm-configuration value: ~e" + config)) ;; ---------------------------------------- (define (merge-options opts c) - (let loop ([c (cdr c)] [opts opts]) - (cond - [(and (pair? c) - (keyword? (car c))) - (loop (cddr c) - (hash-set opts (car c) (cadr c)))] - [else opts]))) + (for/fold ([opts opts]) ([(k v) (in-hash (farm-config-options c))]) + (hash-set opts k v))) (define (get-opt opts kw [default #f]) (hash-ref opts kw default)) (define (get-content c) - (let loop ([c (cdr c)]) - (if (and (pair? c) - (keyword? (car c))) - (loop (cddr c)) - c))) + (farm-config-content c)) (define (client-name opts) (or (get-opt opts '#:name) @@ -356,16 +168,18 @@ (define (q s) (~a "\"" s "\"")) -(define (client-args server pkgs dist-name dist-dir dist-suffix) +(define (client-args desc server pkgs dist-name dist-base dist-dir dist-suffix) (~a " SERVER=" server " PKGS=" (q pkgs) + " DIST_DESC=" (q desc) " DIST_NAME=" (q dist-name) + " DIST_BASE=" dist-base " DIST_DIR=" dist-dir " DIST_SUFFIX=" (q dist-suffix) " RELEASE_MODE=" (if release? "--release" (q "")))) (define (unix-build c host port user server repo clean? - pkgs dist-name dist-dir dist-suffix) + pkgs dist-name dist-base dist-dir dist-suffix) (define dir (or (get-opt c '#:dir) "build/plt")) (define (sh . args) @@ -382,12 +196,14 @@ "git pull") (sh "cd " (q dir) " ; " "make -j " j " client" - (client-args server pkgs dist-name dist-dir dist-suffix) + (client-args (client-name c) + server pkgs + dist-name dist-base dist-dir dist-suffix) " CORE_CONFIGURE_ARGS=" (q (apply ~a #:separator " " (get-opt c '#:configure null)))))) (define (windows-build c host port user server repo clean? - pkgs dist-name dist-dir dist-suffix) + pkgs dist-name dist-base dist-dir dist-suffix) (define dir (or (get-opt c '#:dir) "build\\plt")) (define bits (or (get-opt c '#:bits) 64)) @@ -407,7 +223,10 @@ (cmd "cd " (q dir) " && \"c:\\Program Files" (if (= bits 64) " (x86)" "") "\\Microsoft Visual Studio 9.0\\vc\\vcvarsall.bat\"" " " vc - " && nmake win32-client" (client-args server pkgs dist-name dist-dir dist-suffix)))) + " && nmake win32-client" + (client-args (client-name c) + server pkgs + dist-name dist-base dist-dir dist-suffix)))) (define (client-build c) (define host (or (get-opt c '#:host) @@ -421,6 +240,8 @@ default-pkgs)) (define dist-name (or (get-opt c '#:dist-name) default-dist-name)) + (define dist-base (or (get-opt c '#:dist-base) + default-dist-base)) (define dist-dir (or (get-opt c '#:dist-dir) default-dist-dir)) (define dist-suffix (get-opt c '#:dist-suffix "")) @@ -434,7 +255,7 @@ [(unix) unix-build] [else windows-build]) c host port user server repo clean? - pkgs dist-name dist-dir dist-suffix)) + pkgs dist-name dist-base dist-dir dist-suffix)) ;; ---------------------------------------- @@ -479,7 +300,7 @@ (let loop ([config config] [mode 'sequential] [opts (hasheq)]) - (case (car config) + (case (farm-config-tag config) [(parallel sequential) (define new-opts (merge-options opts config)) (define ts diff --git a/pkgs/distro-build/farm.rkt b/pkgs/distro-build/farm.rkt @@ -0,0 +1,313 @@ +#lang racket/base + +;; A build farm is normally run via the `farm' target of the Racket +;; repository's top-level makefile. That target, in turn, uses the +;; `distro-build/drive-clients' module. +;; +;; Each client is built by running commands via `ssh', where the +;; client's host (and optional port and/or user) indicate the ssh +;; target. Each client machine must be set up with a public-key +;; authenticaion, because a direct `ssh' is expected to work without a +;; password prompt. +;; +;; On the client machine, all work is performed with a git clone at a +;; specified directory. The directory defaults to "build/plt" (Unix, +;; Mac OS X) or "build\\plt" (Windows). If the directory exists +;; already on a client machine (and the machine is not configured for +;; "clean" mode), then the directory is assumed to be a suitable git +;; clone, and it is updated with `git pull'. Otherwise, a git +;; repository is cloned; by default, the server is used as the source +;; git repository (so that the server and client are in sync). +;; +;; If a build fails for a machine, building continues on other +;; machines. Success for a given machine means that its installer +;; ends up in "build/installers" (and failure for a machine means no +;; installer) as recorded in the "table.rktd" file. +;; +;; Machine Requirements +;; -------------------- +;; +;; Each Unix or Mac OS X client needs the following available: +;; +;; * ssh server with public-key authentication +;; * git +;; * gcc, make, etc. +;; +;; Each Windows client needs the following: +;; +;; * git +;; * Microsoft Visual Studio 9.0 (2008), installed in the +;; default folder: +;; C:\Program Files\Microsoft Visual Studio 9.0 (32-bit host) +;; C:\Program Files (x86)\Microsoft Visual Studio 9.0 (64-bit host) +;; * Nullsoft Scriptable Install System (NSIS), installed in the +;; default folder: +;; C:\Program Files\NSIS\makensis.exe +;; or C:\Program Files (x86)\NSIS\makensis.exe +;; or instaled so that `makensis' in in yur PATH. +;; +;; Farm Configuration +;; ------------------- +;; +;; A farm configuration module is normally wriiten in the +;; `distro-build/farm' language. The configuration describes +;; individual machines, and groups them with `parallel' or +;; `sequential' to indicate whether the machine's builds should run +;; sequentially or in parallel. Options specified at `parallel' or +;; `sequential' are propagated to eachmachine in the group. +;; +;; For example, a configuration module might look like this: +;; +;; #lang distro-build/farm +;; +;; (sequential +;; #:server "192.168.56.1" +;; (machine +;; #:desc "Linux (32-bit, Precise Pangolin)" +;; #:name "Ubuntu 32" +;; #:vbox "Ubuntu 12.04" +;; #:host "192.168.56.102") +;; (machine +;; #:desc "Windows (64-bit)" +;; #:name "Windows 64" +;; #:vbox "Windows 7" +;; #:host "192.168.56.103" +;; #:port 2022 +;; #:dir "c:\\Users\\mflatt\\build\\plt" +;; #:platform 'windows +;; #:bits 64)) +;; +;; +;; Farm-configuration keywords (where <string*> means no spaces, etc.): +;; +;; #:host <string*> --- defaults to "localhost" +;; #:port <integer> --- ssh port for the client; defaults to 22 +;; #:user <string*> --- ssh user for the client; defaults to current user +;; #:dir <string> --- defaults to "build/plt" or "build\\plt" +;; #:server <string*> --- the address of the server as accessed by the +;; client; defaults to the `server' command-line +;; argument +;; #:repo <string> --- the git repository for Racket; defaults to +;; "http://<server>:9440/.git" +;; #:pkgs '(<string*> ...) --- packages to install; defaults to +;; `PKGS' in the makfile (or, more genereally, +;; the `pkgs' command-line argument to +;; `distro-build/drive-clients') +;; #:dist-name <string> --- the distribution name; defaults to the +;; `DIST_NAME' makefile variable or `dist-name' +;; command-line argument +;; #:dist-base <string*> --- the distribution's installater name prefix; +;; defaults to the `DIST_BASE' makefile variable +;; or the `dist-base' command-line argument +;; #:dist-dir <string*> --- the distribution's installation directory; +;; defaults to the `DIST_DIR' makefile variable +;; or the `dist-dir' command-line argument +;; #:dist-suffix <string*> --- a suffix for the installer's name, usually +;; used for an OS variant; defaults to the +;; `DIST_SUFFIX' makefile variable or the +;; `dist-suffix' command-line argument +;; #:max-vm <real> --- max number of VMs allowed to run with this +;; machine, counting the machine; defaults to 1 +;; #:vbox <string> --- Virtual Box machine name; if provided the +;; virtual machine is started and stopped as needed +;; #:platform <symbol> --- 'windows or 'unix, defaults to 'unix +;; #:configure '(<string> ...) --- arguments to `configure' +;; #:bits <integer> --- 32 or 64, affects Visual Studio path +;; #:vc <string*> --- "x86" or "x64" to select the Visual C build mode; +;; default depends on bits +;; #:j <integer> --- parallelism for `make' on Unix and Mac OS X; +;; defaults to 1 +;; #:timeout <number> --- numbers of seconds to wait before declaring +;; failure; defaults to 30 minutes +;; #:clean? <boolean> --- if true, then the build process on the client +;; machine starts by removing <dir>; the default +;; is #f, but the `--clean' command-line flag +;; changes the default to #t +;; +;; Machine-only keywords: +;; #:name <string> --- defaults to host; this string is recorded as +;; a description of the installer (for use in a +;; generated table of installer links, for example) +;; +;; +;; More precisely, the `distro-build/farm' language is like +;; `racket/base' except that the module body must have exactly one +;; expression (plus any number of definitions, etc.) that produces a +;; farm-configuration value. The value is exported as `farm-config' +;; from the module. Any module can act as a farm-configuration module +;; a long as it exports `farm-config' as a farm-configuration value. +;; +;; The `distro-build/farm' language also adds the following functions +;; to `racket/base': +;; +;; (machine <opt-kw> <opt-val> ... ...) -> farm-config? +;; Produces a farm configuration based on the given keyword-based +;; options. The support keyword arguments are described above. +;; +;; (sequential <opt-kw> <opt-val> ... ... config ...) +;; -> farm-config? +;; config : farm-config? +;; Produces a farm configuration that runs each `config' +;; sequentially. The support keyword arguments are described above. +;; +;; (parallel <opt-kw> <opt-val> ... ... config ...) +;; -> farm-config? +;; config : farm-config? +;; Produces a farm configuration that runs each `config' in +;; parallel. The support keyword arguments are described above. +;; +;; (farm-config? v) -> boolean? +;; (farm-config-tag config) -> (or/c 'machine 'sequential 'parallel) +;; config : farm-config? +;; (farm-config-options config) -> (hash/c keyword? any/c) +;; config : farm-config? +;; (farm-config-content config) -> (listof farm-config?) +;; config : farm-config? +;; Farm configuation inspection +;; +;; (current-mode) -> string? +;; (current-mode s) -> void? +;; s : string? +;; A parameter whose value is the user's requested mode for this +;; configuration. The default mode is "default". The interpretation +;; of modes is completely up to the farm-configuration file. + +;; ---------------------------------------- + +(require racket/format + (for-syntax syntax/kerncase + racket/base)) + +(provide (except-out (all-from-out racket/base) + #%module-begin) + (rename-out [module-begin #%module-begin]) + sequential + parallel + machine + farm-config? + farm-config-tag + farm-config-options + farm-config-content + current-mode) + +(module reader syntax/module-reader + distro-build/farm) + +(struct farm-config (tag options content)) + +(define-syntax-rule (module-begin form ...) + (#%plain-module-begin (farm-begin #f form ...))) + +(define-syntax (farm-begin stx) + (syntax-case stx () + [(_ #t) #'(begin)] + [(_ #f) + (raise-syntax-error 'farm + "did not find an expression for the farm configuration")] + [(_ found? next . rest) + (let ([expanded (local-expand #'next 'module (kernel-form-identifier-list))]) + (syntax-case expanded (begin) + [(begin next1 ...) + #`(farm-begin found? next1 ... . rest)] + [(id . _) + (and (identifier? #'id) + (ormap (lambda (kw) (free-identifier=? #'id kw)) + (syntax->list #'(require + provide + define-values + define-syntaxes + begin-for-syntax + module + module* + #%require + #%provide)))) + #`(begin #,expanded (farm-begin found? . rest))] + [_else + (if (syntax-e #'found?) + (raise-syntax-error 'farm + "found second top-level expression" + #'next) + #`(begin + (provide farm-config) + (define farm-config (let ([v #,expanded]) + (unless (farm-config? v) + (error 'farm + (~a "expression did not produce a farm configuration\n" + " result: ~e\n" + " expression: ~.s") + v + 'next)) + v)) + (farm-begin + #t + . rest)))]))])) + +(define sequential + (make-keyword-procedure + (lambda (kws kw-vals . subs) + (constructor kws kw-vals subs + check-group-keyword 'sequential)))) +(define parallel + (make-keyword-procedure + (lambda (kws kw-vals . subs) + (constructor kws kw-vals subs + check-group-keyword 'sequential)))) +(define machine + (make-keyword-procedure + (lambda (kws kw-vals) + (constructor kws kw-vals null + check-machine-keyword 'machine)))) + +(define (constructor kws kw-vals subs check tag) + (farm-config + tag + (for/hash ([kw (in-list kws)] + [val (in-list kw-vals)]) + (unless (check kw val) + (error tag + (~a "bad value for keyword\n" + " keyword: ~s" + " value: ~e") + kw + val)) + (values kw val)) + (for/list ([sub subs]) + (unless (farm-config? sub) + (raise-argument-error tag "farm-config?" sub)) + sub))) + +(define (check-group-keyword kw val) + (case kw + [(#:pkgs) (and (list? val) (andmap simple-string? val))] + [(#:dist-name) (string? val)] + [(#:dist-dir) (simple-string? val)] + [(#:dist-suffix) (simple-string? val)] + [(#:max-vm) (real? val)] + [(#:server) (simple-string? val)] + [(#:host) (simple-string? val)] + [(#:user) (simple-string? val)] + [(#:port) (and (exact-integer? val) (<= 1 val 65535))] + [(#:dir) (string? val)] + [(#:vbox) (string? val)] + [(#:platform) (memq val '(unix windows))] + [(#:configure) (and (list? val) (andmap string? val))] + [(#:bits) (or (equal? val 32) (equal? val 64))] + [(#:vc) (or (equal? val "x86") (equal? val "x64"))] + [(#:timeout) (real? val)] + [(#:j) (exact-positive-integer? val)] + [(#:repo) (string? val)] + [(#:clean?) (boolean? val)] + [else #f])) + +(define (check-machine-keyword kw val) + (case kw + [(#:name) (string? val)] + [else (check-group-keyword kw val)])) + +(define (simple-string? s) + (and (string? s) + ;; No spaces, quotes, or other things that could + ;; break a command-line, path, or URL construction: + (regexp-match #rx"^[-a-zA-A0-9.]*$" s))) + +(define current-mode (make-parameter "default")) diff --git a/pkgs/distro-build/installer-dmg.rkt b/pkgs/distro-build/installer-dmg.rkt @@ -108,9 +108,9 @@ (system*/show hdiutil "detach" mnt) (delete-directory mnt)) -(define (installer-dmg human-name dir-name dist-suffix) +(define (installer-dmg human-name base-name dist-suffix) (define dmg-name (format "bundle/~a-~a~a.dmg" - dir-name + base-name (system-library-subpath #f) dist-suffix)) (make-dmg human-name "bundle/racket" dmg-name bg-image) diff --git a/pkgs/distro-build/installer-exe.rkt b/pkgs/distro-build/installer-exe.rkt @@ -397,14 +397,14 @@ SectionEnd (parameterize ([current-directory "bundle"]) (system* makensis "/V3" "installer.nsi"))) -(define (installer-exe human-name dir-name release? dist-suffix) +(define (installer-exe human-name base-name release? dist-suffix) (define makensis (or (find-executable-path "makensis.exe") (try-exe "c:\\Program Files\\NSIS\\makensis.exe") (try-exe "c:\\Program Files (x86)\\NSIS\\makensis.exe") (error 'installer-exe "cannot find \"makensis.exe\""))) (define platform (let-values ([(base name dir?) (split-path (system-library-subpath #f))]) (path->string name))) - (define exe-path (format "bundle/~a-~a-win32~a.exe" dir-name platform dist-suffix)) + (define exe-path (format "bundle/~a-~a-win32~a.exe" base-name platform dist-suffix)) (nsis-generate exe-path human-name (version) diff --git a/pkgs/distro-build/installer-sh.rkt b/pkgs/distro-build/installer-sh.rkt @@ -69,9 +69,9 @@ (system/show "chmod" "+x" dest) (delete-file tmp-tgz)) -(define (installer-sh human-name dir-name release? dist-suffix) +(define (installer-sh human-name base-name dir-name release? dist-suffix) (define sh-path (format "bundle/~a-~a~a.sh" - dir-name + base-name (system-library-subpath #f) dist-suffix)) (generate-installer-sh "bundle/racket" sh-path diff --git a/pkgs/distro-build/installer.rkt b/pkgs/distro-build/installer.rkt @@ -9,18 +9,22 @@ (define release? #f) (define upload-to #f) +(define upload-desc "") -(define-values (short-human-name human-name dir-name dist-suffix) +(define-values (short-human-name human-name base-name dir-name dist-suffix) (command-line #:once-each [("--release") "Create a release installer" (set! release? #t)] [("--upload") url "Upload installer" (set! upload-to url)] + [("--desc") desc "Description to accompany upload" + (set! upload-desc desc)] #:args - (human-name dir-name dist-suffix) + (human-name base-name dir-name dist-suffix) (values human-name (format "~a v~a" human-name (version)) + (format "~a-~a" base-name (version)) (if release? dir-name (format "~a-~a" dir-name (version))) @@ -30,14 +34,16 @@ (define installer-file (case (system-type) - [(unix) (installer-sh human-name dir-name release? dist-suffix)] - [(macosx) (installer-dmg human-name dir-name dist-suffix)] - [(windows) (installer-exe short-human-name dir-name release? dist-suffix)])) + [(unix) (installer-sh human-name base-name dir-name release? dist-suffix)] + [(macosx) (installer-dmg human-name base-name dist-suffix)] + [(windows) (installer-exe short-human-name base-name release? dist-suffix)])) (call-with-output-file* (build-path "bundle" "installer.txt") #:exists 'truncate/replace - (lambda (o) (fprintf o "~a\n" installer-file))) + (lambda (o) + (fprintf o "~a\n" installer-file) + (fprintf o "~a\n" upload-desc))) (when upload-to (printf "Upload ~a to ~a\n" installer-file upload-to) @@ -46,6 +52,7 @@ (string->url (format "~aupload/~a" upload-to (path->string (file-name-from-path installer-file)))) - (file->bytes installer-file))) + (file->bytes installer-file) + (list (string-append "Description: " upload-desc)))) (unless (equal? (read i) #t) (error "file upload failed"))) diff --git a/pkgs/distro-build/serve-catalog.rkt b/pkgs/distro-build/serve-catalog.rkt @@ -68,6 +68,27 @@ (define (write-info req pkg-name) (response/sexpr (pkg-name->info req pkg-name))) +(define (record-installer dir filename desc) + (when desc + (define table-file (build-path dir "table.rktd")) + (call-with-file-lock/timeout + #:max-delay 2 + table-file + 'exclusive + (lambda () + (define t (hash-set + (if (file-exists? table-file) + (call-with-input-file* table-file read) + (hash)) + desc + filename)) + (call-with-output-file table-file + #:exists 'truncate/replace + (lambda (o) + (write t o) + (newline o)))) + void))) + (define (receive-file req filename) (unless (relative-path? filename) (error "upload path name must be relative")) @@ -77,6 +98,11 @@ #:exists 'truncate/replace (lambda (o) (write-bytes (request-post-data/raw req) o))) + (define desc + (for/or ([h (in-list (request-headers/raw req))]) + (and (equal? (header-field h) #"Description") + (bytes->string/utf-8 (header-value h))))) + (record-installer dir filename desc) (response/sexpr #t)) (define-values (dispatch main-url)