www

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

commit 771e9300ca10ac14d75808665f3973a3deaaaf76
parent ee514c1c63144db893e2c84cfba27d556923bb8b
Author: Matthew Flatt <mflatt@racket-lang.org>
Date:   Tue,  2 Jul 2013 09:28:39 -0600

Change "farm" terminology to "site", mostly

original commit: 2e657af9b6473cb2aef4b4e8e40135b90c720dea

Diffstat:
Apkgs/distro-build/assemble-site.rkt | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apkgs/distro-build/config.rkt | 374+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apkgs/distro-build/download-page.rkt | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpkgs/distro-build/drive-clients.rkt | 22+++++++++++-----------
Dpkgs/distro-build/farm.rkt | 374-------------------------------------------------------------------------------
Mpkgs/distro-build/install-pkgs.rkt | 2+-
Mpkgs/distro-build/set-config.rkt | 2+-
Mpkgs/distro-build/url-options.rkt | 2+-
8 files changed, 551 insertions(+), 388 deletions(-)

diff --git a/pkgs/distro-build/assemble-site.rkt b/pkgs/distro-build/assemble-site.rkt @@ -0,0 +1,64 @@ +#lang racket/base +(require racket/cmdline + racket/file + net/url + "download-page.rkt" + (only-in "site.rkt" extract-options)) + +(define build-dir (build-path "build")) +(define dest-dir (build-path build-dir "site")) + +(define built-dir (build-path build-dir "built")) + +(define installers-dir (build-path "installers")) +(define pkgs-dir (build-path "pkgs")) +(define catalog-dir (build-path "catalog")) + +(define-values (config-file config-mode) + (command-line + #:args + (config-file config-mode) + (values config-file config-mode))) + +(define config (extract-options config-file config-mode)) + +(define (copy dir [build-dir build-dir]) + (make-directory* dest-dir) + (printf "Copying ~s\n" (build-path build-dir dir)) + (copy-directory/files (build-path build-dir dir) + (build-path dest-dir dir) + #:keep-modify-seconds? #t)) + +(delete-directory/files dest-dir #:must-exist? #f) +(copy pkgs-dir built-dir) + +(printf "Building catalog\n") +(let ([c-dir (build-path built-dir catalog-dir "pkg")] + [d-dir (build-path dest-dir catalog-dir "pkg")]) + (make-directory* d-dir) + (define base-url (string->url (hash-ref config '#:dist-base-url))) + (for ([f (in-list (directory-list c-dir))]) + (define ht (call-with-input-file* (build-path c-dir f) read)) + (define new-ht + (hash-set ht 'source (url->string + (combine-url/relative + base-url + (path->string + (build-path + "pkgs" + (path-add-suffix f #".zip"))))))) + (call-with-output-file* + (build-path d-dir f) + (lambda (o) + (write new-ht o) + (newline o))))) + +(copy installers-dir) + +(make-download-page (build-path build-dir + installers-dir + "table.rktd") + #:installers-url "installers/" + #:dest (build-path dest-dir + "index.html") + #:git-clone (current-directory)) diff --git a/pkgs/distro-build/config.rkt b/pkgs/distro-build/config.rkt @@ -0,0 +1,374 @@ +#lang racket/base + +;; A build farm is normally run via the `installers' target of the +;; Racket repository's top-level makefile. That target, in turn, uses +;; the `distro-build/drive-clients' module. +;; +;; The server machine first prepares packages for installation on +;; clients. The site configuration's top-level entry is consulted for +;; a `#:pkgs' and/or `#:doc-search' option, which overrides any `PKGS' +;; and/or `DOC_SEARCH' configuration from the makefile. +;; +;; The site configuration file otherwise describes and configures +;; client machines. 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. +;; +;; Site Configuration +;; ------------------- +;; +;; A site configuration module is normally wriiten in the +;; `distro-build/config' 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 each machine in the group. +;; +;; For example, a configuration module might look like this: +;; +;; #lang distro-build/config +;; +;; (sequential +;; #:pkgs '("drracket") +;; #: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)) +;; +;; +;; Site-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 makefile (or, particularly, +;; the `pkgs' command-line argument to +;; `distro-build/drive-clients') +;; #:dist-base-url <string> --- a URL that is used to construct +;; a default for #:doc-search and +;; #:dist-catalogs, where the +;; constructed values are consistent +;; with converting a build server's +;; content into a download site; since +;; URLs are constructed via relative +;; paths, this URL normally should end +;; with a slash +;; #:doc-search <string> --- URL to install as the configuration +;; for remote documentation searches in +;; generated installers; "" is replaced +;; with the PLT default; defaults to +;; #:dist-base-url (if present) extended +;; with "doc/search.html", or the +;; `DOC_SEARCH' makefile variable (or the +;; `doc-search' argument) +;; #:dist-name <string> --- the distribution name; defaults to the +;; `DIST_NAME' makefile variable (or the +;; `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) +;; #:dist-catalogs '(<string> ...) --- catalog URLs to install as the +;; initial catalog configuration +;; in generated installed, where +;; "" is replaced with the PLT +;; default catalogs; defaults to +;; #:dist-base-url (if present) +;; extended with "catalogs" in a +;; list followed by "" +;; #: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>; set this +;; to #f for a shared repo checkout; the default +;; is determined by the `CLEAN_MODE' makefile +;; variable (or `--clean' command-line flag) +;; #:pull? <boolean> --- if true, then the build process on the client +;; machine starts by a `git pull' in <dir>; set +;; to #f, for example, for a repo checkout that is +;; shared with server; the default is #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/config' language is like +;; `racket/base' except that the module body must have exactly one +;; expression (plus any number of definitions, etc.) that produces a +;; site-configuration value. The value is exported as `site-config' +;; from the module. Any module can act as a site-configuration module +;; a long as it exports `site-config' as a site-configuration value. +;; +;; The `distro-build/config' language also adds the following functions +;; to `racket/base': +;; +;; (machine <opt-kw> <opt-val> ... ...) -> site-config? +;; Produces a site configuration based on the given keyword-based +;; options. The support keyword arguments are described above. +;; +;; (sequential <opt-kw> <opt-val> ... ... config ...) +;; -> site-config? +;; config : site-config? +;; Produces a site configuration that runs each `config' +;; sequentially. The support keyword arguments are described above. +;; +;; (parallel <opt-kw> <opt-val> ... ... config ...) +;; -> site-config? +;; config : site-config? +;; Produces a site configuration that runs each `config' in +;; parallel. The support keyword arguments are described above. +;; +;; (site-config? v) -> boolean? +;; (site-config-tag config) -> (or/c 'machine 'sequential 'parallel) +;; config : site-config? +;; (site-config-options config) -> (hash/c keyword? any/c) +;; config : site-config? +;; (site-config-content config) -> (listof site-config?) +;; config : site-config? +;; Site configuation inspection +;; +;; (current-mode) -> string? +;; (current-mode s) -> void? +;; s : string? +;; A parameter whose value is the user's requested mode for this +;; configuration, normally as provided via the makefile's +;; `CONFIG_MODE' variable. The default mode is "default". The +;; interpretation of modes is completely up to the +;; site 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 + site-config? + site-config-tag + site-config-options + site-config-content + current-mode + extract-options) + +(module reader syntax/module-reader + distro-build/site) + +(struct site-config (tag options content)) + +(define-syntax-rule (module-begin form ...) + (#%plain-module-begin (site-begin #f form ...))) + +(define-syntax (site-begin stx) + (syntax-case stx () + [(_ #t) #'(begin)] + [(_ #f) + (raise-syntax-error 'site + "did not find an expression for the site configuration")] + [(_ found? next . rest) + (let ([expanded (local-expand #'next 'module (kernel-form-identifier-list))]) + (syntax-case expanded (begin) + [(begin next1 ...) + #`(site-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 (site-begin found? . rest))] + [_else + (if (syntax-e #'found?) + (raise-syntax-error 'site + "found second top-level expression" + #'next) + #`(begin + (provide site-config) + (define site-config (let ([v #,expanded]) + (unless (site-config? v) + (error 'site + (~a "expression did not produce a site configuration\n" + " result: ~e\n" + " expression: ~.s") + v + 'next)) + v)) + (site-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) + (site-config + tag + (for/hash ([kw (in-list kws)] + [val (in-list kw-vals)]) + (define r (check kw val)) + (when (eq? r 'bad-keyword) + (error tag + (~a "unrecognized keyword for option\n" + " keyword: ~s") + kw)) + (unless (check kw val) + (error tag + (~a "bad value for keyword\n" + " keyword: ~s\n" + " value: ~e") + kw + val)) + (values kw val)) + (for/list ([sub subs]) + (unless (site-config? sub) + (raise-argument-error tag "site-config?" sub)) + sub))) + +(define (check-group-keyword kw val) + (case kw + [(#:pkgs) (and (list? val) (andmap simple-string? val))] + [(#:doc-search) (string? val)] + [(#:dist-name) (string? val)] + [(#:dist-base) (simple-string? val)] + [(#:dist-dir) (simple-string? val)] + [(#:dist-suffix) (simple-string? val)] + [(#:dist-catalogs) (and (list? val) (andmap string? val))] + [(#:dist-base-url) (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)] + [(#:pull?) (boolean? val)] + [else 'bad-keyword])) + +(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")) + +(define (extract-options config-file config-mode) + (or + (and (file-exists? config-file) + (parameterize ([current-mode config-mode]) + (site-config-options + (dynamic-require (path->complete-path config-file) 'site-config)))) + (hash))) + diff --git a/pkgs/distro-build/download-page.rkt b/pkgs/distro-build/download-page.rkt @@ -0,0 +1,99 @@ +#lang racket/base +(require racket/format + racket/path + racket/system + net/url + openssl/sha1 + xml) + +(provide make-download-page) + +(module+ main + (require racket/cmdline) + + (define args null) + (define (arg! kw val) + (set! args (cons (cons kw val) args))) + + (define table-file + (command-line + #:once-each + [("--at") url "URL for installaters reletaive to download page" + (arg! '#:installers-url url)] + [("--dest") file "Write to <dest>" + (arg! '#:dest file)] + [("--git") dir "Report information from git clone <dir>" + (arg! '#:git-clone dir)] + #:args + (table-file) + table-file)) + + (let ([args (sort args keyword<? #:key car)]) + (keyword-apply make-download-page + (map car args) + (map cdr args) + table-file))) + +(define (make-download-page table-file + #:dest [dest "index.html"] + #:installers-url [installers-url "./"] + #:title [title "Racket Downloads"] + #:git-clone [git-clone #f]) + + (define table (call-with-input-file table-file read)) + + (unless (hash? table) + (raise-user-error + 'make-download-page + (~a "given file does not contain a hash table\n" + " file: ~a") + table-file)) + + (define (system*/string . args) + (define s (open-output-string)) + (parameterize ([current-output-port s]) + (apply system* args)) + (get-output-string s)) + + (call-with-output-file* + dest + #:exists 'truncate/replace + (lambda (o) + (parameterize ([empty-tag-shorthand html-empty-tags]) + (write-xexpr + `(html + (head (title ,title) + (style ,(~a " .detail { font-size: small; }" + " .checksum, .path { font-family: monospace }"))) + (body + (h2 ,title) + (table + ,@(for/list ([key (in-list (sort (hash-keys table) string<?))]) + (define inst (hash-ref table key)) + `(tr (td (a ((href ,(url->string + (combine-url/relative + (string->url installers-url) + inst)))) + ,key)) + (td nbsp) + (td (span ([class "detail"]) + "SHA1: " + (span ([class "checksum"]) + ,(call-with-input-file* + (build-path (path-only table-file) + inst) + sha1))))))) + ,@(if git-clone + (let ([git (find-executable-path "git")]) + (define origin (let ([s (system*/string git "remote" "show" "origin")]) + (define m (regexp-match #rx"(?m:Fetch URL: (.*)$)" s)) + (if m + (cadr m) + "???"))) + (define stamp (system*/string git "log" "-1" "--format=%H")) + `((p + (div (span ([class "detail"]) "Repository: " (span ([class "path"]) ,origin))) + (div (span ([class "detail"]) "Commit: " (span ([class "checksum"]) ,stamp)))))) + null))) + o) + (void))))) diff --git a/pkgs/distro-build/drive-clients.rkt b/pkgs/distro-build/drive-clients.rkt @@ -5,13 +5,13 @@ racket/format racket/file racket/string - (only-in "farm.rkt" + (only-in "config.rkt" current-mode - farm-config? - farm-config-tag farm-config-options farm-config-content) + site-config? + site-config-tag site-config-options site-config-content) "url-options.rkt") -;; See "farm.rkt" for an overview. +;; See "config.rkt" for an overview. ;; ---------------------------------------- @@ -35,24 +35,24 @@ dist-name dist-base dist-dir))) (define config (parameterize ([current-mode config-mode]) - (dynamic-require (path->complete-path config-file) 'farm-config))) + (dynamic-require (path->complete-path config-file) 'site-config))) -(unless (farm-config? config) +(unless (site-config? config) (error 'drive-clients - "configuration module did not provide a farm-configuration value: ~e" + "configuration module did not provide a site-configuration value: ~e" config)) ;; ---------------------------------------- (define (merge-options opts c) - (for/fold ([opts opts]) ([(k v) (in-hash (farm-config-options c))]) + (for/fold ([opts opts]) ([(k v) (in-hash (site-config-options c))]) (hash-set opts k v))) (define (get-opt opts kw [default #f]) (hash-ref opts kw default)) (define (get-content c) - (farm-config-content c)) + (site-config-content c)) (define (client-name opts) (or (get-opt opts '#:name) @@ -333,12 +333,12 @@ [mode 'sequential] [opts (hasheq)]) (unless stop? - (case (farm-config-tag config) + (case (site-config-tag config) [(parallel sequential) (define new-opts (merge-options opts config)) (define ts (map (lambda (c) (loop c - (farm-config-tag config) + (site-config-tag config) new-opts)) (get-content config))) (define (wait) diff --git a/pkgs/distro-build/farm.rkt b/pkgs/distro-build/farm.rkt @@ -1,374 +0,0 @@ -#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. -;; -;; The server machine first prepares packages for installation on -;; clients. The farm configuration's top-level entry is consulted for -;; a `#:pkgs' and/or `#:doc-search' option, which overrides any `PKGS' -;; and/or `DOC_SEARCH' configuration from the makefile. -;; -;; The farm configuration file otherwise describes and configures -;; client machines. 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 each machine in the group. -;; -;; For example, a configuration module might look like this: -;; -;; #lang distro-build/farm -;; -;; (sequential -;; #:pkgs '("drracket") -;; #: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 makefile (or, particularly, -;; the `pkgs' command-line argument to -;; `distro-build/drive-clients') -;; #:dist-base-url <string> --- a URL that is used to construct -;; a default for #:doc-search and -;; #:dist-catalogs, where the -;; constructed values are consistent -;; with converting a build server's -;; content into a download site; since -;; URLs are constructed via relative -;; paths, this URL normally should end -;; with a slash -;; #:doc-search <string> --- URL to install as the configuration -;; for remote documentation searches in -;; generated installers; "" is replaced -;; with the PLT default; defaults to -;; #:dist-base-url (if present) extended -;; with "doc/search.html", or the -;; `DOC_SEARCH' makefile variable (or the -;; `doc-search' argument) -;; #:dist-name <string> --- the distribution name; defaults to the -;; `DIST_NAME' makefile variable (or the -;; `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) -;; #:dist-catalogs '(<string> ...) --- catalog URLs to install as the -;; initial catalog configuration -;; in generated installed, where -;; "" is replaced with the PLT -;; default catalogs; defaults to -;; #:dist-base-url (if present) -;; extended with "catalogs" in a -;; list followed by "" -;; #: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>; set this -;; to #f for a shared repo checkout; the default -;; is determined by the `CLEAN_MODE' makefile -;; variable (or `--clean' command-line flag) -;; #:pull? <boolean> --- if true, then the build process on the client -;; machine starts by a `git pull' in <dir>; set -;; to #f, for example, for a repo checkout that is -;; shared with server; the default is #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, normally as provided via the makefile's -;; `CONFIG_MODE' variable. 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 - extract-options) - -(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)]) - (define r (check kw val)) - (when (eq? r 'bad-keyword) - (error tag - (~a "unrecognized keyword for option\n" - " keyword: ~s") - kw)) - (unless (check kw val) - (error tag - (~a "bad value for keyword\n" - " keyword: ~s\n" - " 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))] - [(#:doc-search) (string? val)] - [(#:dist-name) (string? val)] - [(#:dist-base) (simple-string? val)] - [(#:dist-dir) (simple-string? val)] - [(#:dist-suffix) (simple-string? val)] - [(#:dist-catalogs) (and (list? val) (andmap string? val))] - [(#:dist-base-url) (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)] - [(#:pull?) (boolean? val)] - [else 'bad-keyword])) - -(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")) - -(define (extract-options config-file config-mode) - (or - (and (file-exists? config-file) - (parameterize ([current-mode config-mode]) - (farm-config-options - (dynamic-require (path->complete-path config-file) 'farm-config)))) - (hash))) - diff --git a/pkgs/distro-build/install-pkgs.rkt b/pkgs/distro-build/install-pkgs.rkt @@ -1,7 +1,7 @@ #lang racket/base (require racket/cmdline racket/string - (only-in "farm.rkt" extract-options)) + (only-in "site.rkt" extract-options)) (define-values (config-file config-mode default-pkgs flags) (command-line diff --git a/pkgs/distro-build/set-config.rkt b/pkgs/distro-build/set-config.rkt @@ -2,7 +2,7 @@ (require racket/cmdline racket/file racket/path - (only-in "farm.rkt" extract-options) + (only-in "config.rkt" extract-options) "url-options.rkt") (define-values (dest-config-file config-file config-mode default-doc-search default-catalogs) diff --git a/pkgs/distro-build/url-options.rkt b/pkgs/distro-build/url-options.rkt @@ -17,6 +17,6 @@ (let ([v (hash-ref config '#:dist-base-url #f)]) (and v (list (url->string - (combine-url/relative (string->url v) "catalog")) + (combine-url/relative (string->url v) "catalog/")) ""))) default-catalogs))