remove obsolte build support
Much of the old build support turned into "distro-build" for package-based builds, and the "build" directory hasn't been used for a year or so.
This commit is contained in:
parent
0d25969ff0
commit
6621e48b86
File diff suppressed because it is too large
Load Diff
|
@ -1,525 +0,0 @@
|
|||
#!/bin/env racket
|
||||
;; -*- scheme -*-
|
||||
|
||||
#lang racket/base
|
||||
|
||||
(require racket/cmdline racket/runtime-path racket/match racket/promise
|
||||
racket/list ; for use in specs too
|
||||
racket/string
|
||||
racket/file (only-in racket/system system)
|
||||
(except-in compatibility/mlist mappend)
|
||||
meta/checker (prefix-in dist: meta/dist-specs) meta/specs)
|
||||
|
||||
(define (/-ify x)
|
||||
(regexp-replace #rx"/?$" (if (path? x) (path->string x) x) "/"))
|
||||
(define home/ (/-ify (expand-user-path "~scheme")))
|
||||
(define binaries/ (/-ify (build-path home/ "binaries")))
|
||||
(define target/ (/-ify (build-path home/ "pre-installers")))
|
||||
(define racket/ (/-ify (or (getenv "PLTHOME")
|
||||
(error 'bundle "PLTHOME is not defined"))))
|
||||
(define racket-base/ (/-ify (simplify-path (build-path racket/ 'up) #f)))
|
||||
(define racket/-name (let-values ([(base name dir?) (split-path racket/)])
|
||||
(path-element->string name)))
|
||||
|
||||
(define cd current-directory)
|
||||
|
||||
(define *readme-file*
|
||||
(build-path racket/ "README"))
|
||||
(define *info-domain-file*
|
||||
(build-path racket/ "collects" "info-domain" "compiled" "cache.rktd"))
|
||||
|
||||
(define *readme-cache* #f)
|
||||
(define *info-domain-cache* #f)
|
||||
|
||||
(define-runtime-path *spec-file* "distribution-specs")
|
||||
|
||||
(define *verify?* #t)
|
||||
(define *btgz?* #t)
|
||||
(define *pack?* #t)
|
||||
(define *release?* #f)
|
||||
(define *verbose?* 'yes) ; #t, #f, or else -- show stderr stuff but not stdout
|
||||
|
||||
;;; ===========================================================================
|
||||
;;; Utilities etc
|
||||
|
||||
(define concat string-append)
|
||||
|
||||
(define (sort* l)
|
||||
(sort l string<?))
|
||||
|
||||
(define (dir-list . args)
|
||||
(sort* (map path->string (apply directory-list args))))
|
||||
|
||||
(define (dprintf fmt . args)
|
||||
(when *verbose?*
|
||||
(apply fprintf (current-error-port) fmt args)
|
||||
(flush-output (current-error-port))))
|
||||
|
||||
;;; ===========================================================================
|
||||
;;; Tree utilities
|
||||
|
||||
;; path -> tree
|
||||
;; Same as get-tree, but lists the contents of a tgz file via tar.
|
||||
(define (get-tgz-tree tgz)
|
||||
(define base (regexp-replace #rx"/$" (path->string (cd)) ""))
|
||||
(define tgz-name
|
||||
(regexp-replace #rx"^.*/" (if (path? tgz) (path->string tgz) tgz) ""))
|
||||
(define (tree+rest paths curdir)
|
||||
(define cur-rx (regexp (concat "^" (regexp-quote curdir))))
|
||||
(define m
|
||||
(let ([m (and (pair? paths)
|
||||
(regexp-match-positions cur-rx (car paths)))])
|
||||
(and m (regexp-match-positions #rx"/.*/" (car paths) (cdar m)))))
|
||||
(if m
|
||||
;; we have too many "/"s => need to reconstruct a fake intermediate dir
|
||||
(tree+rest (cons (substring (car paths) 0 (add1 (caar m))) paths) curdir)
|
||||
(let loop ([paths paths] [contents '()])
|
||||
(when (pair? paths)
|
||||
(prop-set! (car paths) 'tgz tgz-name)
|
||||
(prop-set! (car paths) 'base base)
|
||||
(prop-set!
|
||||
(car paths) 'name
|
||||
(cond [(regexp-match #rx"^(?:.*/)?([^/]+)/?$" (car paths)) => cadr]
|
||||
[else (error 'get-tgz-tree
|
||||
"bad path name: ~s" (car paths))])))
|
||||
(if (and (pair? paths) (regexp-match? cur-rx (car paths)))
|
||||
;; still in the same subtree
|
||||
(if (regexp-match? #rx"/$" (car paths))
|
||||
;; new directory
|
||||
(let-values ([(tree rest) (tree+rest (cdr paths) (car paths))])
|
||||
(loop rest (cons tree contents)))
|
||||
;; new file
|
||||
(loop (cdr paths) (cons (car paths) contents)))
|
||||
;; in a new subtree
|
||||
(values (cons curdir (reverse contents)) paths)))))
|
||||
(define-values (p pout pin perr)
|
||||
(subprocess #f /dev/null-in (current-error-port) /tar "tzf" tgz))
|
||||
(parameterize ([current-input-port pout])
|
||||
(let loop ([lines '()])
|
||||
(let ([line (read-line)])
|
||||
(if (eof-object? line)
|
||||
(let ([paths (sort* (reverse lines))])
|
||||
(subprocess-wait p)
|
||||
(unless (eq? 0 (subprocess-status p))
|
||||
(error 'get-tgz-tree "`tar' failed."))
|
||||
(let-values ([(tree rest) (tree+rest paths "")])
|
||||
(if (null? rest)
|
||||
(cdr tree)
|
||||
(error 'get-tgz-tree "something bad happened (~s...)"
|
||||
(car paths)))))
|
||||
(loop (cons line lines)))))))
|
||||
|
||||
;;; ===========================================================================
|
||||
;;; Start working
|
||||
|
||||
(register-macros!)
|
||||
|
||||
(define *platforms* #f)
|
||||
(define *bin-types* #f)
|
||||
(define *src-types* #f)
|
||||
(define *platform-tree-lists* #f)
|
||||
(define /pax #f)
|
||||
(define /tar #f)
|
||||
(define /fakeroot #f)
|
||||
(define /dev/null-out #f)
|
||||
(define /dev/null-in #f)
|
||||
|
||||
(define (process-command-line)
|
||||
(command-line
|
||||
#:multi
|
||||
["+d" "Verify dependencies (default)" (set! *verify?* #t)]
|
||||
["-d" "Don't verify dependencies" (set! *verify?* #f)]
|
||||
["+v" "Verbose mode (on stdout)" (set! *verbose?* #t)]
|
||||
["-v" "Normal output (only stderr) (default)" (set! *verbose?* 'yes)]
|
||||
["-q" "Quiet mode" (set! *verbose?* #f)]
|
||||
["+b" "Create binary tgzs (default)" (set! *btgz?* #t)]
|
||||
["-b" "Skip binary tgzs, re-use binary trees" (set! *btgz?* #f)]
|
||||
["+p" "Pack distributions (default)" (set! *pack?* #t)]
|
||||
["-p" "Skip packing" (set! *pack?* #f)]
|
||||
["++release" "Build for a release" (set! *release?* #t)]
|
||||
["-o" dest "Destination directory" (set! target/ (/-ify dest))]
|
||||
["--text" "Stands for -d +v -b -p -r (useful for debugging)"
|
||||
(set!-values (*verify?* *verbose?* *btgz?* *pack?*) (values #f #t #f #f))])
|
||||
(current-verbose-port (and *verbose?* current-error-port)))
|
||||
|
||||
;; specs can have `lambda' expressions to evaluate, do it in this context
|
||||
(define-namespace-anchor bundle-specs)
|
||||
|
||||
(define (read-spec-file file [param *specs*])
|
||||
(process-specs
|
||||
(with-input-from-file file
|
||||
(lambda ()
|
||||
(let loop ([xs '()])
|
||||
(let ([x (read)])
|
||||
(if (eof-object? x) (reverse xs) (loop (cons x xs)))))))
|
||||
param))
|
||||
|
||||
(define (read-specs)
|
||||
(current-namespace (namespace-anchor->namespace bundle-specs))
|
||||
(dprintf "Reading specs...")
|
||||
(dist:register-specs!)
|
||||
(dprintf " done.\n"))
|
||||
|
||||
(define (input-tgz-name? f)
|
||||
(let ([f (if (path? f) (path->string f) f)])
|
||||
;; names of tgzs that are not the generated binary ones
|
||||
(and (regexp-match? #rx"\\.tgz$" f)
|
||||
(not (regexp-match? #rx"-binaries\\.tgz$" f)))))
|
||||
|
||||
(define (initialize)
|
||||
(when *release?* (*environment* (cons 'release (*environment*))))
|
||||
(define (find-exe name)
|
||||
(path->string
|
||||
(or (find-executable-path name #f)
|
||||
(error (format "error: couldn't find a `~a' executable" name)))))
|
||||
(set! /pax (find-exe "pax"))
|
||||
(set! /tar (find-exe "gtar"))
|
||||
(set! /fakeroot (find-exe "fakeroot"))
|
||||
(set! /dev/null-out (open-output-file "/dev/null" #:exists 'append))
|
||||
(set! /dev/null-in (open-input-file "/dev/null"))
|
||||
(unless (directory-exists? target/) (make-directory target/))
|
||||
(let ([d (ormap (lambda (x) (and (not (directory-exists? x)) x))
|
||||
(list home/ racket/ binaries/ target/))])
|
||||
(when d (error 'bundle "directory not found: ~a" d)))
|
||||
(set! *platforms*
|
||||
(parameterize ([cd binaries/])
|
||||
(filter (lambda (x)
|
||||
(and (not (regexp-match? #rx"^[.]" x))
|
||||
(directory-exists? x)))
|
||||
(dir-list))))
|
||||
(set! *bin-types* (map string->symbol *platforms*))
|
||||
(set! *src-types*
|
||||
(let loop ([bins *bin-types*] [r '()])
|
||||
(if (null? bins)
|
||||
(reverse r)
|
||||
(let* ([bin (car bins)] [src (get-tag bin)])
|
||||
(cond
|
||||
[(not src) (error 'binaries "no type assigned to `~.s'" bin)]
|
||||
[(not (= 1 (length src)))
|
||||
(error 'binaries "bad type assignment for `~.s': ~.s" bin src)]
|
||||
[else (loop (cdr bins)
|
||||
(if (memq (car src) r) r (cons (car src) r)))])))))
|
||||
(dprintf "Scanning full tgzs")
|
||||
(set! *platform-tree-lists*
|
||||
(parameterize ([cd binaries/])
|
||||
(map (lambda (platform)
|
||||
(dprintf ".")
|
||||
(parameterize ([cd platform])
|
||||
;; if no btgz *and* "racket" already created then use
|
||||
;; get-tree (useful when debugging stuff so re-use pre made
|
||||
;; ones) should work the same with an old tree
|
||||
(if (and (directory-exists? "racket") (not *btgz?*))
|
||||
(filtered-map
|
||||
(lambda (x) ; only directories contain stuff we need
|
||||
(and (directory-exists? x) (get-tree x "racket")))
|
||||
(dir-list))
|
||||
(let ([trees (filtered-map
|
||||
(lambda (x)
|
||||
(and (file-exists? x) (input-tgz-name? x)
|
||||
(get-tgz-tree x)))
|
||||
(dir-list))])
|
||||
(tag (list (string->symbol platform))
|
||||
(map (lambda (tree) (tree-filter 'binaries tree))
|
||||
(apply append trees)))))))
|
||||
*platforms*)))
|
||||
(dprintf " done.\n")
|
||||
(for-each (lambda (platform trees)
|
||||
(when (null? trees)
|
||||
(error 'binaries "no binaries found for ~s" platform)))
|
||||
*platforms* *platform-tree-lists*)
|
||||
;; Get the racket tree, remove junk and binary stuff
|
||||
(set-racket-tree! racket/ racket-base/ racket/-name *platform-tree-lists*)
|
||||
(set-bin-files-delayed-lists!
|
||||
(delay (map (lambda (trees)
|
||||
(sort* (mappend tree-flatten (add-trees trees))))
|
||||
*platform-tree-lists*))))
|
||||
|
||||
(define (make-info-domain trees)
|
||||
(unless (= 1 (length trees))
|
||||
(error 'make-info-domain "got zero or multiple trees: ~e" trees))
|
||||
(let* ([collects (or (tree-filter "/racket/collects/" (car trees))
|
||||
(error 'make-info-domain "got no collects in tree"))]
|
||||
[info (filter (lambda (x)
|
||||
(define p (car x))
|
||||
(unless (and (list? p)
|
||||
((length p) . >= . 2)
|
||||
(eq? 'info (car p))
|
||||
(andmap bytes? (cdr p)))
|
||||
(error 'bundle "unexpected path form in cache.rktd: ~e" p))
|
||||
(let ([x (string-join (map bytes->string/utf-8 (cdr p)) "/")])
|
||||
(pair? (tree-filter (concat "/racket/collects/" x)
|
||||
collects))))
|
||||
*info-domain-cache*)])
|
||||
(lambda () (write info) (newline))))
|
||||
|
||||
(define readme-skeleton
|
||||
(delay (let ([m (regexp-match #rx"^(.*?\n====+\n)\n*(.*)$" *readme-cache*)])
|
||||
;; title, rest (without generic source reference)
|
||||
(if m
|
||||
(list (cadr m)
|
||||
(regexp-replace #rx"Instructions for building[^\n]*\n\n"
|
||||
(caddr m)
|
||||
""))
|
||||
(error 'readme-skeleton "unexpected toplevel README")))))
|
||||
(define (make-readme)
|
||||
(for-each
|
||||
;; convert to CRLF on Windows
|
||||
(if (memq 'win (*environment*))
|
||||
(lambda (x) (display (regexp-replace* #rx"\r?\n" x "\r\n")))
|
||||
display)
|
||||
`(,(car (force readme-skeleton))
|
||||
"\n"
|
||||
,@(expand-spec 'readme-header)
|
||||
"\n"
|
||||
,(cadr (force readme-skeleton)))))
|
||||
|
||||
(define (create-binaries platform trees)
|
||||
(parameterize ([cd (build-path binaries/ platform)])
|
||||
(let ([full-tgz (concat "racket-"platform"-full.tgz")]
|
||||
[bin-tgz (concat "racket-"platform"-binaries.tgz")]
|
||||
[all-tgzs (filter input-tgz-name?
|
||||
(map path->string (directory-list)))])
|
||||
(unless (and (directory-exists? "racket") (not *btgz?*))
|
||||
(dprintf "Unpacking binaries in ~s ~a\n" platform all-tgzs)
|
||||
;; even if a "racket" directory exists, we just overwrite the same
|
||||
;; stuff
|
||||
(unless (member full-tgz all-tgzs)
|
||||
(error 'create-binaries "~a/~a not found" (cd) full-tgz))
|
||||
(for ([tgz all-tgzs]) (unpack tgz trees)))
|
||||
(when *btgz?*
|
||||
(dprintf "Creating ~s\n" bin-tgz)
|
||||
(when (file-exists? bin-tgz) (delete-file bin-tgz))
|
||||
(let-values ([(p pout pin perr)
|
||||
(subprocess
|
||||
(current-output-port) /dev/null-in (current-error-port)
|
||||
/fakeroot "--"
|
||||
;; see below for flag explanations
|
||||
/pax "-w" "-x" "ustar" "-z" "-f" bin-tgz
|
||||
;; only pack the racket dir (only exception is Libraries
|
||||
;; on OSX, but that has its own dir)
|
||||
"racket")])
|
||||
(subprocess-wait p))))))
|
||||
|
||||
(define (pack archive trees prefix)
|
||||
;; `pax' is used to create the tgz archives -- the main reasons for using it
|
||||
;; is the fact that it can generate portable "ustar" tar files, and that it
|
||||
;; is flexible enough to allow replacing file names, so we can collect files
|
||||
;; from different directories and make them all appear in a single one in the
|
||||
;; resulting archive.
|
||||
(when (eq? #t *verbose?*) (printf "~a:\n" archive))
|
||||
(cond [*pack?*
|
||||
(dprintf " packing...")
|
||||
(when (file-exists? archive) (delete-file archive))
|
||||
(let*-values ([(output) (if (eq? #t *verbose?*)
|
||||
(current-output-port) /dev/null-out)]
|
||||
[(p pout pin perr)
|
||||
;; Note: pax prints converted paths on stderr, so
|
||||
;; silence it too unless verbose. Use only for
|
||||
;; debugging.
|
||||
(subprocess
|
||||
output #f output
|
||||
/fakeroot "--"
|
||||
/pax
|
||||
"-w" ; write
|
||||
"-x" "ustar" ; create a POSIX ustar format
|
||||
"-z" ; gzip the archive
|
||||
"-d" ; dont go down directories implicitly
|
||||
"-s" (format ",^~a,,p" prefix) ; delete base paths
|
||||
"-f" archive ; pack to this file
|
||||
)])
|
||||
(parameterize ([current-output-port pin])
|
||||
(for ([t trees]) (print-tree t 'full)))
|
||||
(close-output-port pin)
|
||||
(subprocess-wait p)
|
||||
(unless (eq? 0 (subprocess-status p))
|
||||
(error 'pack "`pax' failed.")))]
|
||||
[(eq? #t *verbose?*) (for ([t trees]) (print-tree t))])
|
||||
(when (eq? #t *verbose?*) (newline))
|
||||
(flush-output))
|
||||
|
||||
(define (unpack archive trees)
|
||||
;; unpack using tar (doesn't look like there's a way to unpack according to
|
||||
;; files from stdin with pax, and it uses gnu format with @LongLinks).
|
||||
(let-values
|
||||
([(p pout pin perr)
|
||||
(subprocess
|
||||
(current-output-port) #f (current-error-port) /tar
|
||||
"x" ; extract
|
||||
"-z" ; gunzip the archive
|
||||
"-p" ; preserve permissions
|
||||
"--files-from=-" ; read files from stdin
|
||||
"-f" archive ; unpack this file
|
||||
)]
|
||||
[(trees)
|
||||
(map (lambda (t)
|
||||
(tree-filter
|
||||
(lambda (t)
|
||||
;; Problem: if this returns #t/#f only, then the sources can
|
||||
;; come from multiple tgz since each file will be identified
|
||||
;; by itself. But if this is done, then no empty directories
|
||||
;; will be included (see `tree-filter' comment) and this will
|
||||
;; later be a problem (to have an empty dir in the tree but
|
||||
;; not on disk) -- so return '+ and as soon as a root is
|
||||
;; identified with the tgz, all of it will be used.
|
||||
(and
|
||||
(equal? archive
|
||||
(prop-get (tree-path t) 'tgz
|
||||
(lambda ()
|
||||
(error 'unpack
|
||||
"no `tgz' property for ~e" t))))
|
||||
'+))
|
||||
t))
|
||||
trees)])
|
||||
(parameterize ([current-output-port pin])
|
||||
(for ([t trees]) (print-tree t 'only-files)))
|
||||
(close-output-port pin)
|
||||
(subprocess-wait p)
|
||||
(unless (eq? 0 (subprocess-status p)) (error 'unpack "`tar' failed."))))
|
||||
|
||||
;; This code implements the binary filtering of 3m/cgc files, see
|
||||
;; `binary-keep/throw-templates' in "distribution-specs.ss".
|
||||
;; Careful when editing!
|
||||
(define (filter-bintree tree)
|
||||
(define (get-pattern spec)
|
||||
(let ([rx (expand-spec spec)])
|
||||
(if (and (pair? rx) (null? (cdr rx)) (string? (car rx)))
|
||||
(car rx)
|
||||
(error 'filter-bintree "bad value for ~.s: ~e" spec rx))))
|
||||
(define keep-pattern (get-pattern 'binary-keep))
|
||||
(define throw-pattern (get-pattern 'binary-throw))
|
||||
(define keep-rx (regexpify-spec (string-append "*" keep-pattern "*")))
|
||||
(define throw-rx (regexpify-spec (string-append "*" throw-pattern "*")))
|
||||
(define templates
|
||||
(let ([ts (expand-spec 'binary-keep/throw-templates)])
|
||||
(for ([t ts])
|
||||
(unless (and (string? t)
|
||||
;; verify that it has exactly one "<...!...>" pattern
|
||||
(regexp-match? #rx"^[^<!>]*<[^<!>]*![^<!>]*>[^<!>]*$" t))
|
||||
(error 'filter-bintree "bad keep/throw template: ~e" t)))
|
||||
ts))
|
||||
(define (make-matcher x) ; matchers return match-positions or #f
|
||||
(let ([rxs (map (lambda (t)
|
||||
(let* ([x (regexp-replace #rx"!" t x)]
|
||||
[x (object-name (regexpify-spec x #t))]
|
||||
[x (regexp-replace #rx"<(.*)>" x "(\\1)")])
|
||||
(regexp x)))
|
||||
templates)])
|
||||
(lambda (p) (ormap (lambda (rx) (regexp-match-positions rx p)) rxs))))
|
||||
(define (rassoc x l)
|
||||
(and (pair? l) (if (equal? x (cdar l)) (car l) (rassoc x (cdr l)))))
|
||||
(define keep? (make-matcher keep-pattern))
|
||||
(define throw? (make-matcher throw-pattern))
|
||||
(define existing-paths (tree-flatten tree))
|
||||
;; The two `*-paths' values are association lists: ((<path> . <plain>) ...)
|
||||
;; both sides are unique in each list, the lhs is always an existing path
|
||||
(define (find-paths pred? mode rx)
|
||||
(define res '())
|
||||
(let loop ([t tree])
|
||||
(let ([p (tree-path t)])
|
||||
(cond [(pred? p)
|
||||
=> (lambda (m)
|
||||
(let ([plain (string-append (substring p 0 (caadr m))
|
||||
(substring p (cdadr m)))])
|
||||
(when (rassoc plain res)
|
||||
(error 'filter-bintree
|
||||
"two ~s templates have the same plain: ~e -> ~e"
|
||||
mode p plain))
|
||||
(set! res `((,p . ,plain) ,@res)))
|
||||
#t)]
|
||||
[(regexp-match? rx p)
|
||||
;; other matches are not allowed, unless on a directory where
|
||||
;; all files are selected
|
||||
(when (or (not (pair? t))
|
||||
(memq #f (map loop (cdr t))))
|
||||
(error 'filter-bintree
|
||||
"~s path uncovered by patterns: ~e" mode p))
|
||||
#t]
|
||||
[(pair? t) (not (memq #f (map loop (cdr t))))]
|
||||
[else #f])))
|
||||
res)
|
||||
(define keep-paths (find-paths keep? 'keep keep-rx))
|
||||
(define throw-paths (find-paths throw? 'throw throw-rx))
|
||||
(for ([k keep-paths])
|
||||
(when (assoc (car k) throw-paths)
|
||||
(error 'filter-bintree
|
||||
"a path matched both keep and throw patterns: ~s" (car k))))
|
||||
(let* ([ps (map cdr keep-paths)]
|
||||
[ps (append ps (remove* ps (map cdr throw-paths)))]
|
||||
[scan (lambda (f paths)
|
||||
(map (lambda (p) (cond [(f p paths) => car] [else #f])) ps))]
|
||||
[plain (scan member existing-paths)]
|
||||
[keep (scan rassoc keep-paths)]
|
||||
[throw (scan rassoc throw-paths)])
|
||||
(define del
|
||||
(map (lambda (p k t)
|
||||
(cond
|
||||
[(and p k t) (error 'filter-bintree "got keep+throw+plain")]
|
||||
[(or k t) (or t p)]
|
||||
[else (error 'filter-bintree "internal error")]))
|
||||
plain keep throw))
|
||||
(tree-filter `(not (or ,(lambda (t) (and (memq (tree-path t) del) '+))
|
||||
binary-throw-more))
|
||||
tree)))
|
||||
|
||||
;; This is hooked below as a `distribute!' spec macro, and invoked through
|
||||
;; expand-spec.
|
||||
(define (distribute!)
|
||||
(define (distribute tree) (tree-filter 'distribution tree))
|
||||
(let* ([features (filter string? (reverse (*environment*)))]
|
||||
[name (apply concat (cdr (mappend (lambda (x) (list "-" x))
|
||||
features)))]
|
||||
[features (map string->symbol features)]
|
||||
[bin? (memq 'bin features)]
|
||||
[src? (memq 'src features)]
|
||||
[full? (memq 'full features)])
|
||||
(when (and bin? src?)
|
||||
(error 'distribute! "bad configuration (both bin & src): ~e" features))
|
||||
(unless (or bin? src?)
|
||||
(error 'distribute! "bad configuration (both bin & src): ~e" features))
|
||||
(for ([type (if bin? *bin-types* *src-types*)]
|
||||
;; this is unused if bin? is false
|
||||
[bin-trees (if bin? *platform-tree-lists* *src-types*)])
|
||||
(tag (cons type features)
|
||||
(let ([name (format "~a-~a.tgz" name type)])
|
||||
(dprintf "Creating ~s: filtering..." name)
|
||||
(let ([trees (add-trees
|
||||
(cons (distribute (get-racket-tree))
|
||||
(if bin?
|
||||
(tag 'in-binary-tree
|
||||
(map (if full?
|
||||
distribute
|
||||
(lambda (t)
|
||||
(distribute (filter-bintree t))))
|
||||
bin-trees))
|
||||
'())))])
|
||||
(with-output-to-file *readme-file* #:exists 'truncate make-readme)
|
||||
(with-output-to-file *info-domain-file* #:exists 'truncate
|
||||
(make-info-domain trees))
|
||||
(pack (concat target/ name) trees
|
||||
(if bin?
|
||||
(format "\\(~a\\|~a~a/\\)" racket-base/ binaries/ type)
|
||||
racket-base/)))
|
||||
(dprintf " done.\n")))))
|
||||
'())
|
||||
(register-spec! 'distribute!
|
||||
(lambda () (when (or *pack?* (eq? #t *verbose?*)) (distribute!))))
|
||||
|
||||
(register-spec! 'verify! (lambda () (when *verify?* (verify!))))
|
||||
|
||||
(define (read-orig-files)
|
||||
(set! *readme-cache* (file->string *readme-file*))
|
||||
(set! *info-domain-cache* (with-input-from-file *info-domain-file* read)))
|
||||
(define (write-orig-files)
|
||||
(display-to-file *readme-cache* *readme-file* #:exists 'truncate)
|
||||
(with-output-to-file *info-domain-file* #:exists 'truncate
|
||||
(lambda () (write *info-domain-cache*) (newline))))
|
||||
|
||||
(process-command-line)
|
||||
(read-specs)
|
||||
(initialize)
|
||||
(for-each create-binaries *platforms* *platform-tree-lists*)
|
||||
(dynamic-wind
|
||||
(lambda () (read-orig-files))
|
||||
;; Start the verification and distribution
|
||||
(lambda () (expand-spec 'distributions) (void))
|
||||
(lambda () (write-orig-files)))
|
|
@ -1,128 +0,0 @@
|
|||
# these should be writable (for the web server)
|
||||
cache="/tmp/racket-build-status-cache"
|
||||
cachelock="$cache-lock"
|
||||
requestfile="/tmp/racket-build-request"
|
||||
requeststatusfile="/tmp/racket-build-request-status"
|
||||
|
||||
printf 'Content-type: text/plain\r\nAccess-Control-Allow-Origin: *\r\n\r\n'
|
||||
|
||||
if [[ "$PATH_INFO" = "/request" ]]; then
|
||||
error() { echo "Error: $*"; exit 0; }
|
||||
if [[ -e "$lockfile" ]]; then
|
||||
if [[ -e "$statusfile" ]]; then error "a build is in progress"
|
||||
else error "builds temporarily disabled"; fi
|
||||
fi
|
||||
request_rx='^([^&@]+@racket-lang[.]org)&([^&]+)&([0-9]+)$'
|
||||
if [[ ! "$QUERY_STRING" =~ $request_rx ]]; then error "invalid request"; fi
|
||||
username="${BASH_REMATCH[1]}"
|
||||
branch="${BASH_REMATCH[2]}"
|
||||
cookie="${BASH_REMATCH[3]}"
|
||||
date="$(date +'%Y-%m-%d %H:%M')"
|
||||
prevuser=""
|
||||
if [[ -e "$requestfile" ]]; then
|
||||
prevuser="$(cat "$requestfile" | head -1)"
|
||||
rm -f "$requestfile" || error "could not remove previous request file"
|
||||
rm -f "$requeststatusfile"
|
||||
fi
|
||||
touch "$requestfile" || error "could not create request file"
|
||||
{ echo "$username"; echo "$branch"; echo "$date"; echo "$cookie"; } \
|
||||
> "$requestfile"
|
||||
if [[ "x$prevuser" = "x" ]]; then
|
||||
echo "Request created for $username"
|
||||
elif [[ "x$prevuser" = "x$username" ]]; then
|
||||
echo "Request re-created for $username"
|
||||
else
|
||||
echo "Request created for $username, overwriting request for $prevuser"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
# status reporting
|
||||
|
||||
# cache status reports (avoids excessive work during builds)
|
||||
# use a lockfile as a cheap hack to time cache refreshing
|
||||
if ! lockfile -r 0 -l 25 -s 0 "$cachelock" >& /dev/null \
|
||||
&& [[ -e "$cache" ]]; then
|
||||
cat "$cache"; exit
|
||||
fi
|
||||
|
||||
{
|
||||
|
||||
check_exists() { if [[ -e "$2" ]]; then eval "$1=Y"; else eval "$1=N"; fi; }
|
||||
check_exists L "$lockfile"
|
||||
check_exists S "$statusfile"
|
||||
check_exists SL "$statusfile_last"
|
||||
check_exists R "$requestfile"
|
||||
check_exists RS "$requeststatusfile"
|
||||
|
||||
if [[ "$L$S" = "YY" ]]; then
|
||||
time_for_file() {
|
||||
local t="$(($(date +"%s") - $(stat -c "%Z" "$1")))"
|
||||
printf "%d:%02d:%02d" "$((t/3600))" "$(((t%3600)/60))" "$((t%60))"
|
||||
}
|
||||
printf '{{{LINKTO: %s}}}' "current-$(basename "$buildlogfile")"
|
||||
printf 'A build is running (%s)\n' "$(time_for_file "$lockfile")"
|
||||
printf 'Status: %s (%s)\n' "$(cat "$statusfile")" \
|
||||
"$(time_for_file "$statusfile")"
|
||||
shopt -s nullglob
|
||||
if [[ "x$(echo "$bglogfile"*)" != "x" ]]; then
|
||||
printf '\n%s build jobs running:\n' "$(ls "$bglogfile"* | wc -l)"
|
||||
for bg in "$bglogfile"*; do
|
||||
s="$(grep "^### <<< .* >>>" "$bg" | tail -1 \
|
||||
| sed -e 's/([^()]* build) //' \
|
||||
| sed -e 's/^### <<< \(.*\) >>>/\1/')"
|
||||
printf '{{{LINKTO: %s}}}' "current-$(basename "$bg")"
|
||||
if [[ "x$s" = "x" ]]; then
|
||||
printf ' %s: (just starting)\n' "${bg#$bglogfile-}"
|
||||
else
|
||||
s="${bg#$bglogfile-}: $s"
|
||||
s="$(echo "$s" \
|
||||
| sed -e 's/^\(.*\): \(.*\) \[\1(\(.*\))\]$/\3(\1): \2/')"
|
||||
echo " $s"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
else
|
||||
printf 'No build is running.\n'
|
||||
if [[ "$L" = "Y" ]]; then
|
||||
# lockfile exists, but no statusfile
|
||||
printf '(Builds temporarily disabled.)\n'
|
||||
elif [[ "$S" = "Y" ]]; then
|
||||
# statusfile exists, but no lockfile
|
||||
printf '(Last build crashed abnormally: status file not removed.)\n'
|
||||
fi
|
||||
if [[ "$R" = "Y" ]]; then
|
||||
echo ""
|
||||
{ read R_user; read R_branch; read R_date; } < "$requestfile"
|
||||
printf 'Pending build request for %s' "$R_user"
|
||||
if [[ "x$R_branch" != "xmaster" ]]; then
|
||||
printf ' (%s branch)' "$R_branch"
|
||||
fi
|
||||
echo " made at $R_date"
|
||||
if [[ "$RS" = "Y" ]]; then awk '{ print " " $0 }' < "$requeststatusfile"
|
||||
else echo " The request is fresh, and was not noticed by the system."; fi
|
||||
fi
|
||||
if [[ "$SL" = "Y" ]]; then
|
||||
echo ""
|
||||
last="$(cat "$statusfile_last")"
|
||||
printf '{{{LINKTO: %s}}}' "current-$(basename "$buildlogfile")"
|
||||
if [[ "x$last" = "xDone ("*")" ]]; then
|
||||
last="${last#Done (}"
|
||||
last="${last%)}"
|
||||
printf 'Last build successfully ended at %s\n' "$last"
|
||||
elif [[ "x$last" = "x("*" build) Done ("*")" ]]; then
|
||||
last="${last#(}"
|
||||
build="${last% build) Done*}"
|
||||
last="${last#*) Done (}"
|
||||
last="${last%)}"
|
||||
printf 'Last %s build successfully ended at %s\n' "$build" "$last"
|
||||
else
|
||||
printf 'Last build was unsuccessful (%s)\n' "$last"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
} > "$cache.$$" 2>&1
|
||||
mv "$cache.$$" "$cache"
|
||||
cat "$cache"
|
Binary file not shown.
Before Width: | Height: | Size: 4.9 KiB |
|
@ -1,194 +0,0 @@
|
|||
#lang racket/base
|
||||
|
||||
(require slideshow racket/gui/base racket/runtime-path)
|
||||
|
||||
(provide plt-title-background
|
||||
make-plt-title-background
|
||||
plt-red-color
|
||||
plt-blue-color
|
||||
plt-background-color
|
||||
plt-lambda-color
|
||||
plt-pen-color
|
||||
plt-pen-style)
|
||||
|
||||
(define plt-red-color (make-object color% 242 183 183))
|
||||
(define plt-blue-color (make-object color% 183 202 242))
|
||||
(define plt-background-color (make-object color% 209 220 248))
|
||||
(define plt-lambda-color (send the-color-database find-color "white"))
|
||||
(define plt-pen-color "black")
|
||||
(define plt-pen-style 'transparent)
|
||||
|
||||
(define (with-dc-settings dc thunk)
|
||||
(define alpha (send dc get-alpha))
|
||||
(define smoothing (send dc get-smoothing))
|
||||
(define pen (send dc get-pen))
|
||||
(define brush (send dc get-brush))
|
||||
(thunk)
|
||||
(send* dc (set-alpha alpha)
|
||||
(set-smoothing smoothing)
|
||||
(set-pen pen)
|
||||
(set-brush brush)))
|
||||
|
||||
(define (make-plt-title-background
|
||||
red-color blue-color background-color lambda-color pen-color pen-style
|
||||
#:clip? [clip? #t] #:edge-cleanup-pen [edge-cleanup-pen #f])
|
||||
(define-syntax-rule (make-path cmd ...)
|
||||
(let ([p (new dc-path%)]) (send* p cmd ...) p))
|
||||
(define left-lambda-path
|
||||
(make-path (move-to 153 44)
|
||||
(line-to 161.5 60)
|
||||
(curve-to 202.5 49 230 42 245 61)
|
||||
(curve-to 280.06 105.41 287.5 141 296.5 186)
|
||||
(curve-to 301.12 209.08 299.11 223.38 293.96 244)
|
||||
(curve-to 281.34 294.54 259.18 331.61 233.5 375)
|
||||
(curve-to 198.21 434.63 164.68 505.6 125.5 564)
|
||||
(line-to 135 572)))
|
||||
(define left-logo-path
|
||||
(make-path (append left-lambda-path)
|
||||
(arc 0 0 630 630 (* 235/360 2 pi) (* 121/360 2 pi) #f)))
|
||||
(define bottom-lambda-path
|
||||
(make-path (move-to 135 572)
|
||||
(line-to 188.5 564)
|
||||
(curve-to 208.5 517 230.91 465.21 251 420)
|
||||
(curve-to 267 384 278.5 348 296.5 312)
|
||||
(curve-to 301.01 302.98 318 258 329 274)
|
||||
(curve-to 338.89 288.39 351 314 358 332)
|
||||
(curve-to 377.28 381.58 395.57 429.61 414 477)
|
||||
(curve-to 428 513 436.5 540 449.5 573)
|
||||
(line-to 465 580)
|
||||
(line-to 529 545)))
|
||||
(define bottom-logo-path
|
||||
(make-path (append bottom-lambda-path)
|
||||
(arc 0 0 630 630 (* 314/360 2 pi) (* 235/360 2 pi) #f)))
|
||||
(define right-lambda-path
|
||||
(make-path (move-to 153 44)
|
||||
(curve-to 192.21 30.69 233.21 14.23 275 20)
|
||||
(curve-to 328.6 27.4 350.23 103.08 364 151)
|
||||
(curve-to 378.75 202.32 400.5 244 418 294)
|
||||
(curve-to 446.56 375.6 494.5 456 530.5 537)
|
||||
(line-to 529 545)))
|
||||
(define right-logo-path
|
||||
(make-path (append right-lambda-path)
|
||||
(arc 0 0 630 630 (* 314/360 2 pi) (* 121/360 2 pi) #t)))
|
||||
(define lambda-path ;; the lambda by itself (no circle)
|
||||
(let ([p (new dc-path%)])
|
||||
(send p append left-lambda-path)
|
||||
(send p append bottom-lambda-path)
|
||||
(let ([t (make-object dc-path%)])
|
||||
(send t append right-lambda-path)
|
||||
(send t reverse)
|
||||
(send p append t))
|
||||
(send p close)
|
||||
p))
|
||||
|
||||
;; (define lambda-path
|
||||
;; (make-path (append left-lambda-path)
|
||||
;; (append bottom-lambda-path)
|
||||
;; (append right-lambda-path)))
|
||||
|
||||
;; This function draws the paths with suitable colors:
|
||||
(define (paint-plt dc dx dy)
|
||||
(send dc set-smoothing 'aligned)
|
||||
(define old-pen (send dc get-pen))
|
||||
(define old-brush (send dc get-brush))
|
||||
(define old-clip (send dc get-clipping-region))
|
||||
(send dc set-pen pen-color 0 pen-style)
|
||||
(cond [(procedure? lambda-color)
|
||||
(with-dc-settings dc
|
||||
(λ () (lambda-color dc)
|
||||
(send dc draw-path lambda-path dx dy)))]
|
||||
[lambda-color
|
||||
(send* dc (set-brush lambda-color 'solid)
|
||||
(draw-path lambda-path dx dy))]
|
||||
[else (void)])
|
||||
;; Draw red regions
|
||||
(cond [(is-a? red-color bitmap%)
|
||||
(define rgn1 (new region% [dc dc]))
|
||||
(define rgn2 (new region% [dc dc]))
|
||||
(send rgn1 set-path left-logo-path dx dy #;(- dx 150) #;(- dy 20))
|
||||
(send rgn2 set-path bottom-logo-path dx dy #;(- dx 150) #;(- dy 20))
|
||||
(send rgn2 union rgn1)
|
||||
(send dc set-clipping-region rgn2)
|
||||
;; the left and top values of the bounding box seem to change over
|
||||
;; time, so I've just put reasonable numbers below.
|
||||
(let-values ([(sw sh) (send dc get-scale)])
|
||||
(send* dc (set-scale 1 1)
|
||||
(draw-bitmap red-color 220 100)
|
||||
(set-scale sw sh)))
|
||||
(send dc set-clipping-region old-clip)
|
||||
(cleanup-edges left-logo-path dc dx dy)
|
||||
(cleanup-edges bottom-logo-path dc dx dy)]
|
||||
[(procedure? red-color)
|
||||
(with-dc-settings dc
|
||||
(λ () (red-color dc)
|
||||
(send* dc (draw-path left-logo-path dx dy)
|
||||
(draw-path bottom-logo-path dx dy))))]
|
||||
[else (send* dc (set-brush red-color 'solid)
|
||||
(draw-path left-logo-path dx dy)
|
||||
(draw-path bottom-logo-path dx dy))])
|
||||
;; Draw blue region
|
||||
(cond [(is-a? blue-color bitmap%)
|
||||
(define rgn (new region% [dc dc]))
|
||||
(send rgn set-path right-logo-path dx dy #;(- dx 150) #;(- dy 20))
|
||||
(send dc set-clipping-region rgn)
|
||||
;; the left and top values of the bounding box seem to change over
|
||||
;; time, so I've just put reasonable numbers below.
|
||||
(let-values ([(sw sh) (send dc get-scale)])
|
||||
(send* dc (set-scale 1 1)
|
||||
(draw-bitmap blue-color 430 50)
|
||||
(set-scale sw sh)))
|
||||
(send dc set-clipping-region old-clip)
|
||||
(cleanup-edges right-logo-path dc dx dy)]
|
||||
[(procedure? blue-color)
|
||||
(with-dc-settings dc
|
||||
(λ () (blue-color dc)
|
||||
(send dc draw-path right-logo-path dx dy)))]
|
||||
[else (send* dc (set-brush blue-color 'solid)
|
||||
(draw-path right-logo-path dx dy))])
|
||||
(send* dc (set-pen old-pen)
|
||||
(set-brush old-brush)
|
||||
(set-clipping-region old-clip)))
|
||||
(define (cleanup-edges path dc dx dy)
|
||||
(when edge-cleanup-pen
|
||||
(define pen (send dc get-pen))
|
||||
(define brush (send dc get-brush))
|
||||
(define alpha (send dc get-alpha))
|
||||
(send* dc (set-pen edge-cleanup-pen)
|
||||
(set-brush "black" 'transparent)
|
||||
(set-alpha .8)
|
||||
(draw-path path dx dy)
|
||||
(set-pen pen)
|
||||
(set-brush brush)
|
||||
(set-alpha alpha))))
|
||||
(define image (pin-over
|
||||
(if background-color
|
||||
(colorize (filled-rectangle client-w client-h)
|
||||
background-color)
|
||||
(blank client-w client-h))
|
||||
320 50
|
||||
(scale (dc paint-plt 630 630 0 0) 12/10)))
|
||||
(if clip? (clip image) image))
|
||||
|
||||
(define plt-title-background
|
||||
(make-plt-title-background plt-red-color
|
||||
plt-blue-color
|
||||
plt-background-color
|
||||
plt-lambda-color
|
||||
plt-pen-color
|
||||
plt-pen-style))
|
||||
|
||||
(define-runtime-path arrow.png "128x128-arrow.png")
|
||||
(define blue-arrow (read-bitmap arrow.png))
|
||||
|
||||
(define result.png "racket-rising.png")
|
||||
|
||||
(define size 1)
|
||||
(define bmp (make-bitmap (round (* 1024 size 2/3)) (* 768 size 1/2)))
|
||||
(define bdc (make-object bitmap-dc% bmp))
|
||||
(draw-pict (scale plt-title-background size) bdc -100 0)
|
||||
(void (send bdc draw-bitmap
|
||||
blue-arrow
|
||||
(/ (- (send bmp get-width) (send blue-arrow get-width)) 2)
|
||||
(/ (- (send bmp get-height) (send blue-arrow get-height)) 2)))
|
||||
(when (send bmp save-file result.png 'png)
|
||||
(printf "wrote ~a\n" result.png))
|
|
@ -1,88 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# This is a very simple job server which can be used to run commands in
|
||||
# a different context. For example, for things that need to run from
|
||||
# inside an OSX session rather than in the ssh-ed context.
|
||||
|
||||
here="$(cd $(dirname "$0"); pwd)"
|
||||
pidfile="$here/pid"
|
||||
|
||||
unset LD_LIBRARY_PATH
|
||||
|
||||
###############################################################################
|
||||
server() {
|
||||
case "$serverstatus" in
|
||||
( running ) echo "Server already running" 1>&2; exit 1 ;;
|
||||
( stopped ) ;;
|
||||
( dead ) echo "Cleaning up after dead server" 1>&2; rm -f "$pidfile" ;;
|
||||
( * ) echo "Unknown server status" 1>&2; exit 1 ;;
|
||||
esac
|
||||
echo "Server started, pid=$$"
|
||||
echo "$$" > "$pidfile"
|
||||
trap cleanup 0 3 9 15
|
||||
while true; do
|
||||
cd "$here"
|
||||
jobs="$(find * -name "*.job")"
|
||||
if [[ "$jobs" = "" ]]; then sleep 2; continue; fi
|
||||
echo "$jobs" | \
|
||||
while read job; do
|
||||
n="${job%.job}"
|
||||
echo "Running job #$n..."
|
||||
cd "$HOME"
|
||||
. "$here/$job" > "$here/$n.out" 2>&1
|
||||
echo "$?" > "$here/$n.ret"
|
||||
cd "$here"
|
||||
echo "Done"
|
||||
rm -f "$here/$job"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
cleanup() { rm -f "$pidfile"; }
|
||||
|
||||
###############################################################################
|
||||
client() {
|
||||
case "$serverstatus" in
|
||||
( running ) ;;
|
||||
( stopped ) echo "No server running" 1>&2; exit 1 ;;
|
||||
( dead ) echo "Server died" 1>&2; exit 1 ;;
|
||||
( * ) echo "Unknown server status" 1>&2; exit 1 ;;
|
||||
esac
|
||||
c="0"
|
||||
if [[ -e "$here/counter" ]]; then c="$(cat "$here/counter")"; fi
|
||||
c=$(( (c+1) % 10000 ))
|
||||
echo "$c" > "$here/counter"
|
||||
c="$here/$c"
|
||||
echo "cd \"$(pwd)\"" > "$c.tmp"
|
||||
if [[ "x$1" = "x-" ]]; then cat; else echo "$@"; fi >> "$c.tmp"
|
||||
mv "$c.tmp" "$c.job"
|
||||
while [[ -e "$c.job" ]]; do sleep 1; done
|
||||
cat "$c.out"; rm -f "$c.out"
|
||||
stat="$(cat "$c.ret")"; rm -f "$c.ret"
|
||||
exit "$stat"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
status() {
|
||||
echo "$serverstatus"
|
||||
}
|
||||
|
||||
if [[ ! -e "$pidfile" ]]; then serverstatus="stopped"
|
||||
else
|
||||
pid="$(cat "$pidfile")"
|
||||
if ps -p "$pid" | grep -q "$pid"; then serverstatus="running"
|
||||
else serverstatus="dead"; fi
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
|
||||
case "x$1" in
|
||||
( "x--help" ) echo "--start: start server"
|
||||
echo "--status: find the status of the running server, if any"
|
||||
echo "Anything else, run it on the server; use \`-' to read"
|
||||
echo " shell code from stdin"
|
||||
exit ;;
|
||||
( "x--start" ) shift; server "$@" ;;
|
||||
( "x--status" ) shift; status "$@" ;;
|
||||
( * ) client "$@" ;;
|
||||
esac
|
|
@ -1,2 +0,0 @@
|
|||
#lang info
|
||||
(define compile-omit-paths 'all)
|
|
@ -1,200 +0,0 @@
|
|||
#!/bin/sh
|
||||
#| -*- scheme -*-
|
||||
exec racket "$0"
|
||||
|
||||
Instructions:
|
||||
|
||||
* Create a copy of a distributed PLT tree, change all files that need to change
|
||||
for the patch. If this is not a first patch, then begin this process with a
|
||||
tree that has the previous patch applied. (Patch numbers should go from 1
|
||||
up.)
|
||||
|
||||
I do this:
|
||||
cd ...git-repo...
|
||||
git checkout -b patch <PREV-VER-OR-PATCH> patched
|
||||
git cherry-pick fix-sha1s...
|
||||
... more merges as needed ...
|
||||
And at the end don't forget to drop a new tag for the patched result.
|
||||
|
||||
* Make sure that "collects/version/patchlevel.ss" contains the new patch
|
||||
number, and add comments about this patch, with a list of files that are
|
||||
modified. (This is good for the next step, when doing additional patches.)
|
||||
|
||||
* In the code below,
|
||||
- set `plt-version' to the version you're patching (base version, the code
|
||||
will expect `(version)' to return an equal value).
|
||||
- set `plt-base' to the location of the patched PLT tree on your system.
|
||||
- put the list of files in the `files' definition. Each patch should also
|
||||
have all preceding patches in it, which means that if you're patching an
|
||||
already-patched tree, then you should add more files. (This is why it is
|
||||
good to keep track of the modified files.) Note that
|
||||
"collects/version/patchlevel.ss" must be included in this list, and that
|
||||
the file does have the correct patchlevel number (there is currently no way
|
||||
to check whether the patchlevel makes sense).
|
||||
|
||||
* Note that the patch is a collection with the same name ("plt-patch" below).
|
||||
This means that installing a patch is a process that first overwrites any
|
||||
preexisting patch collections. This is fine, because patches are linear and
|
||||
cumulative. The worst that can happen is that someone downloads a patch
|
||||
older than what's installed -- in that case the PLT tree already has the
|
||||
higher patch level, and when the collection's installer is doing its work it
|
||||
will simply be skipped (a successful patch installation happens only once,
|
||||
and is later skipped when setup-plt is re-run).
|
||||
|
||||
* Test, put in "iplt/web/download/patches/", publish new html, announce.
|
||||
|
||||
* Commit the patched tree as a new tag.
|
||||
|
||||
|#
|
||||
|
||||
#lang mzscheme
|
||||
|
||||
;; ============================================================================
|
||||
;; customization (items marked with `[*]' should be edited for all patches)
|
||||
|
||||
;; [*] which PLT version is this patch for?
|
||||
(define plt-version "370")
|
||||
|
||||
;; [*] location of a patched PLT tree
|
||||
(define plt-base "~/patched")
|
||||
|
||||
;; [*] patched files in this tree (including previously patched files, if any)
|
||||
(define files '("collects/version/patchlevel.ss"
|
||||
"collects/drscheme/private/module-language.ss"
|
||||
"collects/framework/private/scheme.ss"
|
||||
"collects/slideshow/tool.ss"
|
||||
"collects/lang/htdp-langs.ss"
|
||||
"collects/drscheme/private/unit.ss"))
|
||||
|
||||
;; message to show after the last `Done' (#f => no extra text)
|
||||
(define exit-message "please restart DrScheme")
|
||||
|
||||
;; template for the output archive file
|
||||
(define patchfile-template "/tmp/plt-patch-v~ap~a.plt")
|
||||
|
||||
;; template for archive name
|
||||
(define name-template "PLT Scheme v~ap~a patch")
|
||||
|
||||
;; patchlevel file in the PLT tree (must be included in `files' above)
|
||||
(define patchlevel-file "collects/version/patchlevel.ss")
|
||||
|
||||
;; ============================================================================
|
||||
;; code folows
|
||||
|
||||
(require (lib "list.ss") (lib "pack.ss" "setup"))
|
||||
|
||||
;; move patchlevel file to the end
|
||||
(unless (member patchlevel-file files)
|
||||
(error 'make-patch
|
||||
"missing patchlevel file (~a) in the list of files" patchlevel-file))
|
||||
(set! files (append (remove patchlevel-file files) (list patchlevel-file)))
|
||||
|
||||
(unless (absolute-path? plt-base)
|
||||
(error 'make-patch "plt-base is not an absolute path: ~a" plt-base))
|
||||
|
||||
(define patchlevel
|
||||
;; use `dynamic-require' -- not `require' since the patch can be built by a
|
||||
;; different PLT installation
|
||||
(dynamic-require (build-path plt-base patchlevel-file) 'patchlevel))
|
||||
(define archive-name (format name-template plt-version patchlevel))
|
||||
(define archive-filename (format patchfile-template plt-version patchlevel))
|
||||
|
||||
(define unpacker-body
|
||||
`((define me ,(format "v~ap~a-patch" plt-version patchlevel))
|
||||
(define (error* fmt . args)
|
||||
(error (string-append "ERROR applying "me": " (apply format fmt args))))
|
||||
(define (message fmt . args)
|
||||
(printf "*** ~a: ~a\n" me (apply format fmt args)))
|
||||
(define collects-dir (find-collects-dir))
|
||||
(cond
|
||||
[(not (equal? ,plt-version (version)))
|
||||
(error* "bad version number; this patch is for version ~a, you have ~a"
|
||||
',plt-version (version))]
|
||||
[(= patchlevel ,patchlevel) (error* "Already installed")]
|
||||
[(> patchlevel ,patchlevel) (error* "Newer patch installed")]
|
||||
[else (message "Applying patch...")])
|
||||
(mzuntar void)
|
||||
(message "Patch applied successfully, recompiling...")
|
||||
;; return a list of all toplevel collections to recompile
|
||||
;; (define (has-info? c)
|
||||
;; (file-exists? (build-path collects-dir c "info.ss")))
|
||||
;; (let* ([cs (directory-list collects-dir)]
|
||||
;; [cs (filter has-info? cs)]
|
||||
;; [cs (map path->string cs)]
|
||||
;; [cs (sort cs string<?)]
|
||||
;; [cs (map list cs)])
|
||||
;; cs)
|
||||
;; instead of the above, invoke setup-plt directly to avoid installers
|
||||
;; (otherwise, running this .plt from DrScheme on Windows complains about
|
||||
;; not being able to recreate the executable)
|
||||
(let ([x 0])
|
||||
(parameterize ([exit-handler (lambda (n) (set! x n))])
|
||||
(run-setup))
|
||||
(message ,(if exit-message (format "Done, ~a." exit-message) "Done."))
|
||||
(exit x))
|
||||
;; everything below does not matter since we exit above
|
||||
;; (but just in case, return '() so no collections to recompile)
|
||||
'()))
|
||||
|
||||
(define run-setup
|
||||
;; This code is based on setup-go
|
||||
`(module run-setup mzscheme
|
||||
(require (lib "unit.ss") (lib "option-sig.ss" "setup")
|
||||
(lib "option-unit.ss" "setup") (lib "cm.ss"))
|
||||
(define-values/invoke-unit/infer setup:option@)
|
||||
;; settings
|
||||
(clean #f) ; no cleaning
|
||||
(make-zo #t) ; recompile zos
|
||||
(call-install #f) ; no installers
|
||||
(make-launchers #f) ; no launcher recreation
|
||||
(make-so #f) ; no extension compilation
|
||||
(verbose #f) ; be quiet
|
||||
(make-verbose #f) ; be quiet
|
||||
(trust-existing-zos #f) ; recompile files when needed
|
||||
(pause-on-errors #f) ; no interactions
|
||||
(force-unpacks #f) ; not doing any unpacking
|
||||
(compile-mode #f) ; default compilation
|
||||
;; not unpacking, but just in case, make it go into the PLT tree
|
||||
(current-target-plt-directory-getter
|
||||
(lambda (preferred main-collects-parent-dir choices)
|
||||
main-collects-parent-dir))
|
||||
(specific-collections '()) ; no specifics, do all collections
|
||||
(archives '()) ; no archives to unpack
|
||||
(specific-planet-dirs '()) ; no planet stuff
|
||||
;; invoke it
|
||||
(require (lib "setup-unit.ss" "setup")
|
||||
(lib "option-unit.ss" "compiler")
|
||||
(lib "compiler-unit.ss" "compiler")
|
||||
(lib "launcher-unit.ss" "launcher")
|
||||
(lib "dynext-unit.ss" "dynext"))
|
||||
(provide run-setup)
|
||||
(define (run-setup)
|
||||
(invoke-unit (compound-unit/infer (import setup-option^) (export)
|
||||
(link launcher@ dynext:compile@ dynext:link@ dynext:file@
|
||||
compiler:option@ compiler@ setup@))
|
||||
(import setup-option^)))))
|
||||
|
||||
(define unpack-unit
|
||||
`(begin (require (lib "list.ss")
|
||||
(lib "patchlevel.ss" "version")
|
||||
(lib "dirs.ss" "setup"))
|
||||
,run-setup
|
||||
(require run-setup)
|
||||
(unit (import main-collects-parent-dir mzuntar) (export)
|
||||
,@unpacker-body)))
|
||||
|
||||
;; Pack up a .plt file
|
||||
|
||||
(current-directory plt-base)
|
||||
|
||||
(when (file-exists? archive-filename) (delete-file archive-filename))
|
||||
|
||||
(pack-plt archive-filename
|
||||
archive-name
|
||||
files
|
||||
#:requires `((("racket") ()) (("gracket") ()))
|
||||
#:file-mode 'file-replace
|
||||
#:plt-relative? #t
|
||||
#:at-plt-home? #t
|
||||
#:unpack-unit unpack-unit)
|
||||
(printf "Patch file created: ~a\n" archive-filename)
|
|
@ -1,311 +0,0 @@
|
|||
!include "MUI2.nsh"
|
||||
!include "WinVer.nsh"
|
||||
!include "nsDialogs.nsh"
|
||||
|
||||
;; ==================== Configuration
|
||||
|
||||
;; The following should define:
|
||||
;; RKTVersion, RKTVersionLong, RKTHumanName, RKTShortName,
|
||||
;; RKTStartName, RKTDirName, RKTRegName, RKTProgFiles,
|
||||
;; RKTLaunchProgram
|
||||
|
||||
!include racket-defs.nsh
|
||||
|
||||
Name "${RKTHumanName}"
|
||||
OutFile "installer.exe"
|
||||
|
||||
BrandingText "${RKTHumanName}"
|
||||
BGGradient 4040A0 101020
|
||||
|
||||
SetCompressor /SOLID "LZMA"
|
||||
|
||||
InstallDir "${RKTProgFiles}\${RKTDirName}"
|
||||
!ifndef SimpleInstaller
|
||||
InstallDirRegKey HKLM "Software\${RKTRegName}" ""
|
||||
!endif
|
||||
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${RKTStartName}"
|
||||
!define MUI_ICON "installer.ico"
|
||||
!define MUI_UNICON "uninstaller.ico"
|
||||
!define MUI_HEADERIMAGE
|
||||
!define MUI_HEADERIMAGE_BITMAP "header.bmp"
|
||||
!define MUI_HEADERIMAGE_BITMAP_RTL "header-r.bmp"
|
||||
!define MUI_HEADERIMAGE_RIGHT
|
||||
|
||||
!define MUI_WELCOMEFINISHPAGE_BITMAP "welcome.bmp"
|
||||
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "welcome.bmp"
|
||||
|
||||
!define MUI_WELCOMEPAGE_TITLE "${RKTHumanName} Setup"
|
||||
!define MUI_UNWELCOMEPAGE_TITLE "${RKTHumanName} Uninstall"
|
||||
!ifdef SimpleInstaller
|
||||
!define MUI_WELCOMEPAGE_TEXT "This is a simple installer for ${RKTShortName}.$\r$\n$\r$\nIt will only create the Racket folder. To uninstall, simply remove the folder.$\r$\n$\r$\n$_CLICK"
|
||||
!else
|
||||
!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of ${RKTShortName}.$\r$\n$\r$\nPlease close any running Racket applications so the installer can update the relevant system files.$\r$\n$\r$\n$_CLICK"
|
||||
!endif
|
||||
!define MUI_UNWELCOMEPAGE_TEXT "This wizard will guide you through the removal of ${RKTShortName}.$\r$\n$\r$\nBefore starting, make sure no Racket applications are running.$\r$\n$\r$\n$_CLICK"
|
||||
|
||||
!define MUI_FINISHPAGE_TITLE "${RKTHumanName}"
|
||||
!ifdef SimpleInstaller
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION OpenInstDir
|
||||
Function OpenInstDir
|
||||
ExecShell "" "$INSTDIR"
|
||||
FunctionEnd
|
||||
!define MUI_FINISHPAGE_RUN_TEXT "Open the installation folder"
|
||||
!else
|
||||
!define MUI_FINISHPAGE_RUN "$INSTDIR\${RKTLaunchProgram}.exe"
|
||||
!define MUI_FINISHPAGE_RUN_TEXT "Run ${RKTLaunchProgram}"
|
||||
!endif
|
||||
!define MUI_FINISHPAGE_LINK "Visit the Racket web site"
|
||||
!define MUI_FINISHPAGE_LINK_LOCATION "http://racket-lang.org/"
|
||||
|
||||
; !define MUI_UNFINISHPAGE_NOAUTOCLOSE ; to allow users see what was erased
|
||||
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\${RKTRegName}"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
|
||||
|
||||
; Doesn't work on some non-xp machines
|
||||
; !define MUI_INSTFILESPAGE_PROGRESSBAR colored
|
||||
|
||||
VIProductVersion "${RKTVersionLong}"
|
||||
VIAddVersionKey "ProductName" "Racket"
|
||||
VIAddVersionKey "Comments" "This is the Racket language, see http://racket-lang.org/."
|
||||
VIAddVersionKey "CompanyName" "PLT Design Inc."
|
||||
VIAddVersionKey "LegalCopyright" "© PLT Design Inc."
|
||||
VIAddVersionKey "FileDescription" "Racket Installer"
|
||||
VIAddVersionKey "FileVersion" "${RKTVersion}"
|
||||
|
||||
;; ==================== Variables
|
||||
|
||||
!ifndef SimpleInstaller
|
||||
Var MUI_TEMP
|
||||
Var STARTMENU_FOLDER
|
||||
!endif
|
||||
|
||||
;; ==================== Interface
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
; Install
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE myTestInstDir
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!ifndef SimpleInstaller
|
||||
!insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
|
||||
!endif
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
; Uncheck and hide the "run" checkbox on vista, since it will run with
|
||||
; elevated permissions (see also ../nsis-vista-note.txt)
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_SHOW DisableRunCheckBoxIfOnVista
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
Function DisableRunCheckBoxIfOnVista
|
||||
${If} ${AtLeastWinVista}
|
||||
; use EnableWindow instead of ShowWindow to just disable it
|
||||
ShowWindow $mui.FinishPage.Run 0
|
||||
${NSD_Uncheck} $mui.FinishPage.Run
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
!ifndef SimpleInstaller
|
||||
; Uninstall
|
||||
!define MUI_WELCOMEPAGE_TITLE "${MUI_UNWELCOMEPAGE_TITLE}"
|
||||
!define MUI_WELCOMEPAGE_TEXT "${MUI_UNWELCOMEPAGE_TEXT}"
|
||||
; !insertmacro MUI_UNPAGE_WELCOME
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
; !insertmacro MUI_UNPAGE_FINISH
|
||||
!endif
|
||||
|
||||
!ifndef SimpleInstaller
|
||||
!define MUI_CUSTOMFUNCTION_UNGUIINIT un.myGUIInit
|
||||
!endif
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
!ifndef SimpleInstaller
|
||||
!define UNINSTEXE "$INSTDIR\Uninstall.exe"
|
||||
!endif
|
||||
|
||||
;; ==================== Installer
|
||||
|
||||
!ifdef SimpleInstaller
|
||||
Function myTestInstDir
|
||||
IfFileExists "$INSTDIR\*.*" +1 inst_dir_exists
|
||||
MessageBox MB_YESNO "The directory '$INSTDIR' already exists, continue?" /SD IDYES IDYES inst_dir_exists
|
||||
Abort
|
||||
inst_dir_exists:
|
||||
FunctionEnd
|
||||
!else
|
||||
Function myTestInstDir
|
||||
; The assumption is that users might have all kinds of ways to get a Racket
|
||||
; tree, plus, they might have an old wise-based installation, so it is better
|
||||
; to rely on files rather than test registry keys. Note: no version check.
|
||||
; if any of these exist, then we assume it's an old installation
|
||||
IfFileExists "$INSTDIR\Racket.exe" racket_is_installed
|
||||
IfFileExists "$INSTDIR\${RKTLaunchProgram}.exe" racket_is_installed
|
||||
IfFileExists "$INSTDIR\collects" racket_is_installed
|
||||
Goto racket_is_not_installed
|
||||
racket_is_installed:
|
||||
IfFileExists "${UNINSTEXE}" we_have_uninstall
|
||||
MessageBox MB_YESNO "It appears that there is an existing Racket installation in '$INSTDIR', but no Uninstaller was found.$\r$\nContinue anyway (not recommended)?" /SD IDYES IDYES maybe_remove_tree
|
||||
Abort
|
||||
we_have_uninstall:
|
||||
MessageBox MB_YESNO "It appears that there is an existing Racket installation in '$INSTDIR'.$\r$\nDo you want to uninstall it first (recommended)?" /SD IDNO IDNO maybe_remove_tree
|
||||
HideWindow
|
||||
ClearErrors
|
||||
ExecWait '"${UNINSTEXE}" _?=$INSTDIR'
|
||||
IfErrors uninstaller_problematic
|
||||
IfFileExists "$INSTDIR\Racket.exe" uninstaller_problematic
|
||||
IfFileExists "$INSTDIR\GRacket.exe" uninstaller_problematic
|
||||
BringToFront
|
||||
Goto racket_is_not_installed
|
||||
uninstaller_problematic:
|
||||
MessageBox MB_YESNO "Errors in uninstallation!$\r$\nDo you want to quit and sort things out now (highly recommended)?" /SD IDNO IDNO maybe_remove_tree
|
||||
Quit
|
||||
maybe_remove_tree:
|
||||
MessageBox MB_YESNO "Since you insist, do you want to simply remove the previous directory now?$\r$\n(It is really better if you sort this out manually.)" /SD IDYES IDNO racket_is_not_installed
|
||||
RMDir /r $INSTDIR
|
||||
racket_is_not_installed:
|
||||
FunctionEnd
|
||||
!endif
|
||||
|
||||
Section ""
|
||||
SetShellVarContext all
|
||||
|
||||
SetDetailsPrint both
|
||||
DetailPrint "Installing Racket..."
|
||||
SetDetailsPrint listonly
|
||||
SetOutPath "$INSTDIR"
|
||||
File /a /r "racket\*.*"
|
||||
!ifndef SimpleInstaller
|
||||
WriteUninstaller "${UNINSTEXE}" ; Create uninstaller
|
||||
!endif
|
||||
|
||||
!ifndef SimpleInstaller
|
||||
SetDetailsPrint both
|
||||
DetailPrint "Creating Shortcuts..."
|
||||
SetDetailsPrint listonly
|
||||
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
|
||||
SetOutPath "$INSTDIR" ; Make installed links run in INSTDIR
|
||||
CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\DrRacket.lnk" "$INSTDIR\DrRacket.exe"
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Racket Documentation.lnk" "$INSTDIR\Racket Documentation.exe"
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\GRacket.lnk" "$INSTDIR\GRacket.exe"
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Racket.lnk" "$INSTDIR\Racket.exe"
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Racket Folder.lnk" "$INSTDIR"
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "${UNINSTEXE}"
|
||||
!insertmacro MUI_STARTMENU_WRITE_END
|
||||
|
||||
SetDetailsPrint both
|
||||
DetailPrint "Setting Registry Keys..."
|
||||
SetDetailsPrint listonly
|
||||
WriteRegStr HKLM "Software\${RKTRegName}" "" "$INSTDIR" ; Save folder location
|
||||
WriteRegStr HKCR ".rkt" "" "Racket.Document"
|
||||
WriteRegStr HKCR ".rktl" "" "Racket.Document"
|
||||
WriteRegStr HKCR ".rktd" "" "Racket.Document"
|
||||
WriteRegStr HKCR ".ss" "" "Racket.Document"
|
||||
WriteRegStr HKCR ".scm" "" "Racket.Document"
|
||||
WriteRegStr HKCR ".scrbl" "" "Racket.Document"
|
||||
WriteRegStr HKCR "Racket.Document" "" "Racket Document"
|
||||
WriteRegStr HKCR "Racket.Document\DefaultIcon" "" "$INSTDIR\collects\icons\schemedoc.ico"
|
||||
WriteRegStr HKCR "Racket.Document\shell\open\command" "" '"$INSTDIR\DrRacket.exe" "%1"'
|
||||
; Example, in case we want some things like this in the future
|
||||
; WriteRegStr HKCR "Racket.Document\shell\racket" "" "Run with Racket"
|
||||
; WriteRegStr HKCR "Racket.Document\shell\racket\command" "" '"$INSTDIR\Racket.exe" "-r" "%1"'
|
||||
WriteRegStr HKCR ".plt" "" "Racket Setup.Document"
|
||||
WriteRegStr HKCR "Racket Setup.Document" "" "Racket Package"
|
||||
WriteRegStr HKCR "Racket Setup.Document\DefaultIcon" "" "$INSTDIR\collects\icons\schemedoc.ico"
|
||||
WriteRegStr HKCR "Racket Setup.Document\shell\open\command" "" '"$INSTDIR\raco.exe" setup -p "%1"'
|
||||
|
||||
WriteRegExpandStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${RKTRegName}" "UninstallString" '"${UNINSTEXE}"'
|
||||
WriteRegExpandStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${RKTRegName}" "InstallLocation" "$INSTDIR"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${RKTRegName}" "DisplayName" "${RKTHumanName}"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${RKTRegName}" "DisplayIcon" "$INSTDIR\DrRacket.exe,0"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${RKTRegName}" "DisplayVersion" "${RKTVersion}"
|
||||
; used to also have "VersionMajor" & "VersionMinor" but looks like it's not needed
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${RKTRegName}" "HelpLink" "http://racket-lang.org/"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${RKTRegName}" "URLInfoAbout" "http://racket-lang.org/"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${RKTRegName}" "Publisher" "PLT Design Inc."
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${RKTRegName}" "NoModify" "1"
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${RKTRegName}" "NoRepair" "1"
|
||||
!endif
|
||||
|
||||
SetDetailsPrint both
|
||||
DetailPrint "Installation complete."
|
||||
SectionEnd
|
||||
|
||||
;; ==================== Uninstaller
|
||||
|
||||
!ifndef SimpleInstaller
|
||||
|
||||
Function un.myGUIInit
|
||||
; if any of these exist, then we're fine
|
||||
IfFileExists "$INSTDIR\Racket.exe" racket_is_installed_un
|
||||
IfFileExists "$INSTDIR\lib\GRacket.exe" racket_is_installed_un
|
||||
IfFileExists "$INSTDIR\DrRacket.exe" racket_is_installed_un
|
||||
IfFileExists "$INSTDIR\lib\collects" racket_is_installed_un
|
||||
MessageBox MB_YESNO "It does not appear that Racket is installed in '$INSTDIR'.$\r$\nContinue anyway (not recommended)?" /SD IDYES IDYES racket_is_installed_un
|
||||
Abort "Uninstall aborted by user"
|
||||
racket_is_installed_un:
|
||||
FunctionEnd
|
||||
|
||||
Section "Uninstall"
|
||||
SetShellVarContext all
|
||||
|
||||
SetDetailsPrint both
|
||||
DetailPrint "Removing the Racket installation..."
|
||||
SetDetailsPrint listonly
|
||||
Delete "$INSTDIR\*.exe"
|
||||
Delete "$INSTDIR\README*.*"
|
||||
RMDir /r "$INSTDIR\collects"
|
||||
RMDir /r "$INSTDIR\include"
|
||||
RMDir /r "$INSTDIR\lib"
|
||||
RMDir /r "$INSTDIR\doc"
|
||||
;; these exist in Racket-Full installations
|
||||
RMDir /r "$INSTDIR\man"
|
||||
RMDir /r "$INSTDIR\src"
|
||||
Delete "${UNINSTEXE}"
|
||||
RMDir "$INSTDIR"
|
||||
;; if the directory is opened, it will take some time to remove
|
||||
Sleep 1000
|
||||
IfErrors +1 uninstall_inst_dir_ok
|
||||
MessageBox MB_YESNO "The Racket installation at '$INSTDIR' was not completely removed.$\r$\nForce deletion?$\r$\n(Make sure no Racket applications are running.)" /SD IDYES IDNO uninstall_inst_dir_ok
|
||||
RMDir /r "$INSTDIR"
|
||||
IfErrors +1 uninstall_inst_dir_ok
|
||||
MessageBox MB_OK "Forced deletion did not work either, you will need to clean up '$INSTDIR' manually." /SD IDOK
|
||||
uninstall_inst_dir_ok:
|
||||
|
||||
SetDetailsPrint both
|
||||
DetailPrint "Removing Shortcuts..."
|
||||
SetDetailsPrint listonly
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
|
||||
Delete "$SMPROGRAMS\$MUI_TEMP\*.lnk"
|
||||
;; Delete empty start menu parent diretories
|
||||
StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"
|
||||
startMenuDeleteLoop:
|
||||
RMDir $MUI_TEMP
|
||||
GetFullPathName $MUI_TEMP "$MUI_TEMP\.."
|
||||
IfErrors startMenuDeleteLoopDone
|
||||
StrCmp $MUI_TEMP $SMPROGRAMS startMenuDeleteLoopDone startMenuDeleteLoop
|
||||
startMenuDeleteLoopDone:
|
||||
|
||||
SetDetailsPrint both
|
||||
DetailPrint "Removing Registry Keys..."
|
||||
SetDetailsPrint listonly
|
||||
DeleteRegKey /ifempty HKLM "Software\${RKTRegName}\Start Menu Folder"
|
||||
DeleteRegKey /ifempty HKLM "Software\${RKTRegName}"
|
||||
DeleteRegKey HKCR ".rkt"
|
||||
DeleteRegKey HKCR ".rktl"
|
||||
DeleteRegKey HKCR ".rktd"
|
||||
DeleteRegKey HKCR ".ss"
|
||||
DeleteRegKey HKCR ".scm"
|
||||
DeleteRegKey HKCR ".scrbl"
|
||||
DeleteRegKey HKCR "Racket.Document"
|
||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${RKTRegName}"
|
||||
|
||||
SetDetailsPrint both
|
||||
DetailPrint "Uninstallation complete."
|
||||
SectionEnd
|
||||
|
||||
!endif
|
|
@ -1 +0,0 @@
|
|||
opensource@google.com
|
|
@ -1,37 +0,0 @@
|
|||
Copyright (c) 2004, 2005, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of Google Inc. nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
The sitemap_gen.py script is written in Python 2.2 and released to the open
|
||||
source community for continuous improvements under the BSD 2.0 new license,
|
||||
which can be found at:
|
||||
|
||||
http://www.opensource.org/licenses/bsd-license.php
|
|
@ -1,65 +0,0 @@
|
|||
Wed Jun 01 01:00:00 2005 Google Inc. <opensource@google.com>
|
||||
|
||||
* sitemap_gen: initial release:
|
||||
This directory contains Python utilities for creating
|
||||
Sitemaps.
|
||||
|
||||
Mon Jun 13 01:00:00 2005 Google Inc. <opensource@google.com>
|
||||
|
||||
* sitemap_gen.py: v1.1
|
||||
|
||||
[BIG]
|
||||
Not blow up when dealing with international character encodings.
|
||||
|
||||
[MODERATE]
|
||||
Fix platform and Python version issues. In some versions of 2.2
|
||||
and certain platforms, True was not defined. Gak!
|
||||
|
||||
Tue Jul 12 01:00:00 2005 Google Inc. <opensource@google.com>
|
||||
|
||||
* sitemap_gen.py: v1.2
|
||||
|
||||
[MODERATE]
|
||||
Default_file option added to directory walking
|
||||
Support for Extended Logfile Format (IIS's log format)
|
||||
Allow wildcards in the "path" attribute on accesslog and urllist
|
||||
input methods.
|
||||
Running on Python 1.5 should exit cleanly with an error message
|
||||
Stricter processing of configuration files
|
||||
|
||||
[SMALL]
|
||||
XML files written in "text" mode, so linefeeds are correct
|
||||
One more Unicode issue fixed: Sitemap filenames with non-ascii
|
||||
characters had still been problematic
|
||||
In directory walking, the root URL of the walk now gets included
|
||||
In directory walking, URLs to directories now have a "/" appended
|
||||
URLs to files we recognize as our own script's Sitemap output files
|
||||
are suppressed.
|
||||
'suppress_search_engine_notify="0"' now does what you would expect
|
||||
Default priority on URLs is now 0.5 instead of 1.0
|
||||
Priority values written by default to only 4 decimal places
|
||||
URLs to Sitemap files in the Sitemap index file are now encoded
|
||||
according to the user's default_encoding, instead of forcing to UTF-8
|
||||
|
||||
Mon Aug 01 01:00:00 2005 Google Inc. <opensource@google.com>
|
||||
|
||||
* sitemap_gen.py: v1.3
|
||||
|
||||
[BIG]
|
||||
<sitemap ... /> input method added.
|
||||
|
||||
[MODERATE]
|
||||
Use proper IDNA encoding on international domain names. This is
|
||||
only available on Python2.3 or higher.
|
||||
|
||||
[SMALL]
|
||||
Fixed Windows bug where directory walking would generate bad URLs on
|
||||
2+ deep subdirectories
|
||||
|
||||
Wed Nov 03 01:00:00 2005 Google Inc. <opensource@google.com>
|
||||
|
||||
* sitemap_gen.py: v1.4
|
||||
|
||||
[SMALL]
|
||||
Fixed bug where writing a gzipped sitemap would store the server's
|
||||
file path in the archive.
|
|
@ -1,10 +0,0 @@
|
|||
Metadata-Version: 1.0
|
||||
Name: sitemap_gen
|
||||
Version: 1.4
|
||||
Summary: Sitemap Generator
|
||||
Home-page: http://sourceforge.net/projects/goog-sitemapgen/
|
||||
Author: Google Inc.
|
||||
Author-email: opensource@google.com
|
||||
License: BSD
|
||||
Description: UNKNOWN
|
||||
Platform: UNKNOWN
|
|
@ -1,25 +0,0 @@
|
|||
sitemap_gen.py
|
||||
|
||||
Version 1.4
|
||||
|
||||
The sitemap_gen.py script analyzes your web server and generates one or more
|
||||
Sitemap files. These files are XML listings of content you make available on
|
||||
your web server. The files can be directly submitted to search engines as
|
||||
hints for the search engine web crawlers as they index your web site. This
|
||||
can result in better coverage of your web content in search engine indices,
|
||||
and less of your bandwidth spent doing it.
|
||||
|
||||
The sitemap_gen.py script is written in Python and released to the open
|
||||
source community for continuous improvements under the BSD 2.0 new license,
|
||||
which can be found at:
|
||||
|
||||
http://www.opensource.org/licenses/bsd-license.php
|
||||
|
||||
The original release notes for the script, including a walk-through for
|
||||
webmasters on how to use it, can be found at the following site:
|
||||
|
||||
http://www.google.com/webmasters/sitemaps/sitemap-generator.html
|
||||
|
||||
The minimum Python version required is Python 2.2. However, if URLs on
|
||||
your site involve any non-ASCII characters, we strongly recommend
|
||||
Python 2.3 or later, as it better handles encoding issues.
|
|
@ -1,164 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
sitemap_gen.py example configuration script
|
||||
|
||||
This file specifies a set of sample input parameters for the
|
||||
sitemap_gen.py client.
|
||||
|
||||
You should copy this file into "config.xml" and modify it for
|
||||
your server.
|
||||
|
||||
|
||||
********************************************************* -->
|
||||
|
||||
|
||||
<!-- ** MODIFY **
|
||||
The "site" node describes your basic web site.
|
||||
|
||||
Required attributes:
|
||||
base_url - the top-level URL of the site being mapped
|
||||
store_into - the webserver path to the desired output file.
|
||||
This should end in '.xml' or '.xml.gz'
|
||||
(the script will create this file)
|
||||
|
||||
Optional attributes:
|
||||
verbose - an integer from 0 (quiet) to 3 (noisy) for
|
||||
how much diagnostic output the script gives
|
||||
suppress_search_engine_notify="1"
|
||||
- disables notifying search engines about the new map
|
||||
(same as the "testing" command-line argument.)
|
||||
default_encoding
|
||||
- names a character encoding to use for URLs and
|
||||
file paths. (Example: "UTF-8")
|
||||
-->
|
||||
<site
|
||||
base_url="http://www.example.com/"
|
||||
store_into="/var/www/docroot/sitemap.xml.gz"
|
||||
verbose="1"
|
||||
>
|
||||
|
||||
<!-- ********************************************************
|
||||
INPUTS
|
||||
|
||||
All the various nodes in this section control where the script
|
||||
looks to find URLs.
|
||||
|
||||
MODIFY or DELETE these entries as appropriate for your server.
|
||||
********************************************************* -->
|
||||
|
||||
<!-- ** MODIFY or DELETE **
|
||||
"url" nodes specify individual URLs to include in the map.
|
||||
|
||||
Required attributes:
|
||||
href - the URL
|
||||
|
||||
Optional attributes:
|
||||
lastmod - timestamp of last modification (ISO8601 format)
|
||||
changefreq - how often content at this URL is usually updated
|
||||
priority - value 0.0 to 1.0 of relative importance in your site
|
||||
-->
|
||||
<url href="http://www.example.com/stats?q=name" />
|
||||
<url
|
||||
href="http://www.example.com/stats?q=age"
|
||||
lastmod="2004-11-14T01:00:00-07:00"
|
||||
changefreq="yearly"
|
||||
priority="0.3"
|
||||
/>
|
||||
|
||||
|
||||
<!-- ** MODIFY or DELETE **
|
||||
"urllist" nodes name text files with lists of URLs.
|
||||
An example file "example_urllist.txt" is provided.
|
||||
|
||||
Required attributes:
|
||||
path - path to the file
|
||||
|
||||
Optional attributes:
|
||||
encoding - encoding of the file if not US-ASCII
|
||||
-->
|
||||
<urllist path="example_urllist.txt" encoding="UTF-8" />
|
||||
|
||||
|
||||
<!-- ** MODIFY or DELETE **
|
||||
"directory" nodes tell the script to walk the file system
|
||||
and include all files and directories in the Sitemap.
|
||||
|
||||
Required attributes:
|
||||
path - path to begin walking from
|
||||
url - URL equivalent of that path
|
||||
|
||||
Optional attributes:
|
||||
default_file - name of the index or default file for directory URLs
|
||||
-->
|
||||
<directory path="/var/www/icons" url="http://www.example.com/images/" />
|
||||
<directory
|
||||
path="/var/www/docroot"
|
||||
url="http://www.example.com/"
|
||||
default_file="index.html"
|
||||
/>
|
||||
|
||||
|
||||
<!-- ** MODIFY or DELETE **
|
||||
"accesslog" nodes tell the script to scan webserver log files to
|
||||
extract URLs on your site. Both Common Logfile Format (Apache's default
|
||||
logfile) and Extended Logfile Format (IIS's default logfile) can be read.
|
||||
|
||||
Required attributes:
|
||||
path - path to the file
|
||||
|
||||
Optional attributes:
|
||||
encoding - encoding of the file if not US-ASCII
|
||||
-->
|
||||
<accesslog path="/etc/httpd/logs/access.log" encoding="UTF-8" />
|
||||
<accesslog path="/etc/httpd/logs/access.log.0" encoding="UTF-8" />
|
||||
<accesslog path="/etc/httpd/logs/access.log.1.gz" encoding="UTF-8" />
|
||||
|
||||
|
||||
<!-- ** MODIFY or DELETE **
|
||||
"sitemap" nodes tell the script to scan other Sitemap files. This can
|
||||
be useful to aggregate the results of multiple runs of this script into
|
||||
a single Sitemap.
|
||||
|
||||
Required attributes:
|
||||
path - path to the file
|
||||
-->
|
||||
<sitemap path="/var/www/docroot/subpath/sitemap.xml" />
|
||||
|
||||
|
||||
<!-- ********************************************************
|
||||
FILTERS
|
||||
|
||||
Filters specify wild-card patterns that the script compares
|
||||
against all URLs it finds. Filters can be used to exclude
|
||||
certain URLs from your Sitemap, for instance if you have
|
||||
hidden content that you hope the search engines don't find.
|
||||
|
||||
Filters can be either type="wildcard", which means standard
|
||||
path wildcards (* and ?) are used to compare against URLs,
|
||||
or type="regexp", which means regular expressions are used
|
||||
to compare.
|
||||
|
||||
Filters are applied in the order specified in this file.
|
||||
|
||||
An action="drop" filter causes exclusion of matching URLs.
|
||||
An action="pass" filter causes inclusion of matching URLs,
|
||||
shortcutting any other later filters that might also match.
|
||||
If no filter at all matches a URL, the URL will be included.
|
||||
Together you can build up fairly complex rules.
|
||||
|
||||
The default action is "drop".
|
||||
The default type is "wildcard".
|
||||
|
||||
You can MODIFY or DELETE these entries as appropriate for
|
||||
your site. However, unlike above, the example entries in
|
||||
this section are not contrived and may be useful to you as
|
||||
they are.
|
||||
********************************************************* -->
|
||||
|
||||
<!-- Exclude URLs that end with a '~' (IE: emacs backup files) -->
|
||||
<filter action="drop" type="wildcard" pattern="*~" />
|
||||
|
||||
<!-- Exclude URLs within UNIX-style hidden files or directories -->
|
||||
<filter action="drop" type="regexp" pattern="/\.[^/]*" />
|
||||
|
||||
</site>
|
|
@ -1,21 +0,0 @@
|
|||
# To add a list of URLs, make a space-delimited text file. The first
|
||||
# column contains the URL; then you can specify various optional
|
||||
# attributes in the form key=value:
|
||||
#
|
||||
# lastmod = modification time in ISO8601 (YYYY-MM-DDThh:mm:ss+00:00)
|
||||
# changefreq = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' |
|
||||
# 'yearly' | 'never'
|
||||
# priority = priority of the page relative to other pages on the same site;
|
||||
# a number between 0.0 and 1.0, where 0.0 is the lowest priority
|
||||
# and 1.0 is the highest priority
|
||||
#
|
||||
# Note that all URLs must be part of the site, and therefore must begin with
|
||||
# the base_url (e.g., 'http://www.example.com/') as specified in config.xml.
|
||||
#
|
||||
# Any line beginning with a # is a comment.
|
||||
#
|
||||
# Example contents of the file:
|
||||
#
|
||||
# http://www.example.com/foo/bar
|
||||
# http://www.example.com/foo/xxx.pdf lastmod=2003-12-31T14:05:06+00:00
|
||||
# http://www.example.com/foo/yyy?x=12&y=23 changefreq=weekly priority=0.3
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<site base_url="http://pre.plt-scheme.org/"
|
||||
store_into="/home/scheme/html/sitemap.xml.gz"
|
||||
verbose="1">
|
||||
<directory path="/home/scheme/html/"
|
||||
url="http://pre.plt-scheme.org/"
|
||||
default_file="index.html" />
|
||||
<!-- Exclude URLs that end with a '~' (IE: emacs backup files) -->
|
||||
<filter action="drop" type="wildcard" pattern="*~" />
|
||||
<!-- Exclude URLs within UNIX-style hidden files or directories -->
|
||||
<filter action="drop" type="regexp" pattern="/\.[^/]*" />
|
||||
<!-- Exclude .plt files -->
|
||||
<filter action="drop" type="wildcard" pattern="*.plt" />
|
||||
<!-- Exclude possible nested trees -->
|
||||
<filter action="drop" type="regexp" pattern="^http://[^/]*/[0-9]+" />
|
||||
</site>
|
|
@ -1,12 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from distutils.core import setup
|
||||
|
||||
setup(name='sitemap_gen',
|
||||
version='1.4',
|
||||
description='Sitemap Generator',
|
||||
license='BSD',
|
||||
author='Google Inc.',
|
||||
author_email='opensource@google.com',
|
||||
url='http://sourceforge.net/projects/goog-sitemapgen/',
|
||||
)
|
File diff suppressed because it is too large
Load Diff
|
@ -1,765 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (c) 2004, 2005 Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# * Neither the name of Google nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
#
|
||||
# The sitemap_gen.py script is written in Python 2.2 and released to
|
||||
# the open source community for continuous improvements under the BSD
|
||||
# 2.0 new license, which can be found at:
|
||||
#
|
||||
# http://www.opensource.org/licenses/bsd-license.php
|
||||
#
|
||||
|
||||
"""Unit tests for sitemap_gen.py, a script for generating sitemaps
|
||||
for a web server.
|
||||
"""
|
||||
|
||||
# Please be careful that all syntax used in this file can be parsed on
|
||||
# Python 1.5 -- this version check is not evaluated until after the
|
||||
# entire file has been parsed.
|
||||
import sys
|
||||
if sys.hexversion < 0x02020000:
|
||||
print 'This script requires Python 2.2 or later.'
|
||||
print 'Currently run with version: %s' % sys.version
|
||||
sys.exit(1)
|
||||
|
||||
import binascii
|
||||
import fnmatch
|
||||
import gzip
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
import xml.dom.minidom
|
||||
import sitemap_gen
|
||||
|
||||
# True and False were introduced in Python2.2.2
|
||||
try:
|
||||
testTrue=True
|
||||
del testTrue
|
||||
except NameError:
|
||||
True=1
|
||||
False=0
|
||||
|
||||
|
||||
class URLCounter(object):
|
||||
"""Counts returned URLs, determines how many valid v. invalid we get.
|
||||
This is a helper for consuming what the many Input* objects produce."""
|
||||
def __init__(self, root, print_invalid, expected):
|
||||
"""Input:
|
||||
root :: root URL for calling the URL's own Validate()
|
||||
print_invalid :: print to output all invalid URLs
|
||||
expected :: sequence of wildcard filters to validate against
|
||||
"""
|
||||
self._root = root
|
||||
self._print = print_invalid
|
||||
self._expected = expected
|
||||
self._valid = 0
|
||||
self._invalid = 0
|
||||
#end def __init__
|
||||
|
||||
def Reset(self):
|
||||
"""Reset our counts without harming the validity filters."""
|
||||
self._valid = 0
|
||||
self._invalid = 0
|
||||
#end def Reset
|
||||
|
||||
def Valid(self):
|
||||
"""Returns number of valid URLs."""
|
||||
return self._valid
|
||||
#end def Valid
|
||||
|
||||
def Invalid(self):
|
||||
"""Returns number of invalid URLs."""
|
||||
return self._invalid
|
||||
#end def Valid
|
||||
|
||||
def Count(self, url, allow_fragment):
|
||||
"""The 'please consume this URL' function called by the URL producer."""
|
||||
valid = True
|
||||
if valid:
|
||||
valid = url.Validate(self._root, allow_fragment)
|
||||
if valid:
|
||||
for filter in self._expected:
|
||||
valid = fnmatch.fnmatchcase(url.loc, filter)
|
||||
if valid:
|
||||
break
|
||||
if valid:
|
||||
self._valid = self._valid + 1
|
||||
else:
|
||||
if self._print:
|
||||
url.Log(prefix='URLCounter', level=0)
|
||||
self._invalid = self._invalid + 1
|
||||
#end def Count
|
||||
#end class URLCounter
|
||||
|
||||
|
||||
class TestSiteMap(unittest.TestCase):
|
||||
"""Tests the sitemap_gen application."""
|
||||
|
||||
def testTimestampISO8601(self):
|
||||
""" Checks whether the TimestampISO8601 function works. """
|
||||
self.assertEqual(sitemap_gen.TimestampISO8601(23),
|
||||
'1970-01-01T00:00:23Z')
|
||||
self.assertEqual(sitemap_gen.TimestampISO8601(549876543),
|
||||
'1987-06-05T07:29:03Z')
|
||||
#end def testTimestampISO8601
|
||||
|
||||
def testExpandPathAttribute(self):
|
||||
""" Verifies our path globbing function works. """
|
||||
temppath = tempfile.mktemp()
|
||||
tempwild = tempfile.tempdir
|
||||
if tempwild:
|
||||
tempwild = tempwild + os.sep
|
||||
tempwild = tempwild + '*'
|
||||
try:
|
||||
open(temppath, 'w').close()
|
||||
|
||||
dict1 = {}
|
||||
dict2 = {'alpha' : 'beta', 'path' : 'DoesNotExist987654321.xyz'}
|
||||
dict3 = {'alpha' : 'beta', 'path' : tempwild}
|
||||
|
||||
res1 = sitemap_gen.ExpandPathAttribute(dict1, 'path')
|
||||
res2 = sitemap_gen.ExpandPathAttribute(dict2, 'path')
|
||||
res3 = sitemap_gen.ExpandPathAttribute(dict3, 'path')
|
||||
|
||||
self.assertEqual(len(res1), 1)
|
||||
self.assertEqual(res1[0], dict1)
|
||||
|
||||
self.assertEqual(len(res2), 1)
|
||||
self.assertEqual(res2[0], dict2)
|
||||
|
||||
self.assert_(len(res3) >= 1)
|
||||
anymatch = False
|
||||
for res in res3:
|
||||
path = res['path']
|
||||
if path.find(temppath) >= 0:
|
||||
anymatch = True
|
||||
self.assertEqual(res['alpha'], 'beta')
|
||||
self.assert_(anymatch)
|
||||
|
||||
finally:
|
||||
os.unlink(temppath)
|
||||
#end def testExpandPathAttribute
|
||||
|
||||
def testEncoder(self):
|
||||
""" Tests minimal functionality of the learning Unicode codec """
|
||||
ENC_UTF8 = 'UTF-8'
|
||||
ENC_LATIN1 = 'ISO-8859-1'
|
||||
ENC_CYRILLIC = 'ISO-8859-5'
|
||||
|
||||
STR1_LATIN1 = 'has an ' + binascii.a2b_hex('FC') + 'mlat'
|
||||
STR1_UTF8 = 'has an ' + binascii.a2b_hex('C3BC') + 'mlat'
|
||||
STR1_UCS2 = 'has an ' + unichr(252) + 'mlat'
|
||||
|
||||
STR2_LATIN1 = 'DRAGON' + binascii.a2b_hex('A7') + '!'
|
||||
STR2_CYRILLIC = 'DRAGON' + binascii.a2b_hex('FD') + '!'
|
||||
STR2_UCS2 = 'DRAGON' + unichr(167) + '!'
|
||||
|
||||
# Spawn our own encoder instance so we don't abuse the module one.
|
||||
encoder = sitemap_gen.Encoder()
|
||||
|
||||
# Convert Latin-1 to UTF-8, by way of Unicode
|
||||
encoder.SetUserEncoding(ENC_LATIN1)
|
||||
self.assertEqual(encoder.WidenText(STR1_LATIN1, None), STR1_UCS2)
|
||||
self.assertEqual(encoder.NarrowText(STR1_UCS2, ENC_UTF8), STR1_UTF8)
|
||||
|
||||
# Test learning. STR1 has no Cyrillic equivalent, STR2 just changes.
|
||||
encoder.SetUserEncoding(None)
|
||||
encoder._learned = []
|
||||
self.assertEqual(encoder.WidenText(STR2_CYRILLIC, ENC_CYRILLIC), STR2_UCS2)
|
||||
self.assertEqual(encoder.WidenText(STR2_CYRILLIC, None), STR2_UCS2)
|
||||
self.assertEqual(encoder.NarrowText(STR1_UCS2, None), STR1_UTF8)
|
||||
self.assert_(not encoder._learned)
|
||||
self.assertEqual(encoder.NarrowText(STR1_UCS2, ENC_LATIN1), STR1_LATIN1)
|
||||
self.assertEqual(encoder.NarrowText(STR1_UCS2, None), STR1_LATIN1)
|
||||
self.assertEqual(encoder.NarrowText(STR2_UCS2, None), STR2_LATIN1)
|
||||
#end def testEncoder
|
||||
|
||||
def testURL(self):
|
||||
""" Vigorously tests our URL attribute processing. """
|
||||
|
||||
# Test the IsAbsolute method
|
||||
self.assert_(sitemap_gen.URL.IsAbsolute('http://a.b.c/d/e.txt?f=g#h'))
|
||||
self.assert_(sitemap_gen.URL.IsAbsolute('http://a.b.c'))
|
||||
self.assert_(not sitemap_gen.URL.IsAbsolute('http:///d/e.txt?f=g#h'))
|
||||
self.assert_(not sitemap_gen.URL.IsAbsolute('http:a.b.c/d/e.txt?f=g#h'))
|
||||
self.assert_(not sitemap_gen.URL.IsAbsolute('a.b.c/d/e.txt?f=g#h'))
|
||||
self.assert_(not sitemap_gen.URL.IsAbsolute('/d/e.txt?f=g#h'))
|
||||
|
||||
# Canonicalize our base URL
|
||||
BASE_R = 'http://www.example.com/f' + binascii.a2b_hex('F6F6') + '/'
|
||||
BASE_C = 'http://www.example.com/f%F6%F6/'
|
||||
sitemap_gen.encoder.SetUserEncoding('ISO-8859-1')
|
||||
self.assertEqual(sitemap_gen.URL.Canonicalize(BASE_R), BASE_C)
|
||||
|
||||
# Test how canonicalization handles pre-quoted values
|
||||
self.assertEqual(sitemap_gen.URL.Canonicalize(
|
||||
'http://www.example.com/my%25thing'),
|
||||
'http://www.example.com/my%25thing')
|
||||
self.assertEqual(sitemap_gen.URL.Canonicalize(
|
||||
'http://www.example.com/my%thing'),
|
||||
'http://www.example.com/my%25thing')
|
||||
|
||||
# Test IDNA encoding
|
||||
# The generator can only do the "right thing" on Python 2.3 or higher
|
||||
warn = sitemap_gen.output.num_warns
|
||||
if sys.hexversion >= 0x02030000:
|
||||
self.assertEqual(sitemap_gen.URL.Canonicalize(
|
||||
'http://www.' + unichr(252) + 'mlat.com/' + unichr(252) + 'mlat.txt'),
|
||||
'http://www.xn--mlat-zra.com/%FCmlat.txt')
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn)
|
||||
else:
|
||||
self.assertEqual(sitemap_gen.URL.Canonicalize(
|
||||
'http://www.' + unichr(252) + 'mlat.com/' + unichr(252) + 'mlat.txt'),
|
||||
'http://www.%FCmlat.com/%FCmlat.txt')
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn + 2)
|
||||
|
||||
# All valid data
|
||||
warn = sitemap_gen.output.num_warns
|
||||
url1 = sitemap_gen.URL()
|
||||
url1.TrySetAttribute('loc', BASE_R + 'bar.html')
|
||||
url1.TrySetAttribute('lastmod', '1987-06-05T07:29:03Z')
|
||||
url1.TrySetAttribute('changefreq', 'daily')
|
||||
url1.TrySetAttribute('priority', '0.3')
|
||||
self.assert_(url1.Validate(BASE_C, True))
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn)
|
||||
|
||||
# Valid ref, all else invalid
|
||||
warn = sitemap_gen.output.num_warns
|
||||
url2 = sitemap_gen.URL()
|
||||
url2.TrySetAttribute('loc', BASE_C + 'bar.html')
|
||||
url2.TrySetAttribute('lastmod', 'June 1, 2005')
|
||||
url2.TrySetAttribute('changefreq', 'every second')
|
||||
url2.TrySetAttribute('priority', 'infinite')
|
||||
url2.TrySetAttribute('badattr', 'Nope!')
|
||||
self.assert_(url2.Validate(BASE_C, True))
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn + 4)
|
||||
|
||||
# Two URLs with same ref should compare equal
|
||||
self.assertEqual(url1, url2)
|
||||
|
||||
# A ref not based
|
||||
warn = sitemap_gen.output.num_warns
|
||||
url3 = sitemap_gen.URL()
|
||||
url3.TrySetAttribute('loc', 'http://www.example.com/bar/foo.html')
|
||||
self.assert_(not url3.Validate(BASE_C, True))
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn + 1)
|
||||
|
||||
# A fragmentary URL
|
||||
warn = sitemap_gen.output.num_warns
|
||||
url4 = sitemap_gen.URL()
|
||||
url4.TrySetAttribute('loc', '/foo.html')
|
||||
self.assert_(not url4.Validate(BASE_C, False))
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn + 1)
|
||||
url4.TrySetAttribute('loc', '/xyzzy/foo.html')
|
||||
self.assert_(url4.Validate('http://www.example.com/', True))
|
||||
self.assertEqual(url4.loc, 'http://www.example.com/xyzzy/foo.html')
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn + 1)
|
||||
|
||||
# Test a whole sequence of good and bad timestamp values
|
||||
timestamps_good = [
|
||||
'2001',
|
||||
'2001-01',
|
||||
'2001-01-02',
|
||||
'2001-01-03T01:02Z',
|
||||
'2001-01-03T01:02:03Z',
|
||||
'2001-01-03T01:02:03.0123Z',
|
||||
'2001-01-03T01:02+00:00',
|
||||
'2001-01-03T01:02:03-99:99',
|
||||
'2001-01-03T01:02:03.0123+88:88',
|
||||
]
|
||||
timestamps_bad = [
|
||||
'2001:01:03T01:02Z',
|
||||
'2001-01-03T01:02:03.Z',
|
||||
'a2001-01-06T01:02:05-99:99',
|
||||
'2001-01-06T01:02:05-99:99Z',
|
||||
'2001-1-6T01:02:05-99:99',
|
||||
'xyzzy',
|
||||
'2001-01-03T01:02:03.1.2Z',
|
||||
]
|
||||
warn = sitemap_gen.output.num_warns
|
||||
url3.TrySetAttribute('loc', BASE_C + 'foo.html')
|
||||
for ts in timestamps_good:
|
||||
url3.TrySetAttribute('lastmod', ts)
|
||||
self.assert_(url3.Validate(BASE_C, True))
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn)
|
||||
for ts in timestamps_bad:
|
||||
url3.TrySetAttribute('lastmod', ts)
|
||||
self.assert_(url3.Validate(BASE_C, True))
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn + len(timestamps_bad))
|
||||
#end def testURL
|
||||
|
||||
def testFilter(self):
|
||||
""" Test the filtering object """
|
||||
url1 = sitemap_gen.URL()
|
||||
url2 = sitemap_gen.URL()
|
||||
url1.TrySetAttribute('loc', 'http://www.example.com/foo/bar.html')
|
||||
url2.TrySetAttribute('loc', 'http://www.example.com/bar/foo.html')
|
||||
url1.Validate('http://www.example.com', True)
|
||||
url2.Validate('http://www.example.com', True)
|
||||
|
||||
# Arguments
|
||||
error = sitemap_gen.output.num_errors
|
||||
args_bad = [
|
||||
{},
|
||||
{'pattern' : '*', 'type' : 'unknown'},
|
||||
{'pattern' : '*', 'type' : 'wildcard', 'action' : 'look pretty'},
|
||||
{'pattern' : '*', 'type' : 'regexp'},
|
||||
]
|
||||
error = sitemap_gen.output.num_errors
|
||||
for args in args_bad:
|
||||
sitemap_gen.Filter(args)
|
||||
self.assertEqual(sitemap_gen.output.num_errors, error + len(args_bad))
|
||||
|
||||
# Wildcard
|
||||
filt_w = sitemap_gen.Filter({'pattern' : '*/foo/*', 'type' : 'wildcard' })
|
||||
self.assertEqual(filt_w.Apply(url1), False)
|
||||
self.assertEqual(filt_w.Apply(url2), None)
|
||||
|
||||
# Regexp
|
||||
filt_r = sitemap_gen.Filter({'pattern' : '/bar/[^/]+$', 'type' : 'REGEXP',
|
||||
'action' : 'PASS'})
|
||||
self.assertEqual(filt_r.Apply(url1), None)
|
||||
self.assertEqual(filt_r.Apply(url2), True)
|
||||
#end def testFilter
|
||||
|
||||
def Count(self, url, allow_fragment):
|
||||
if url.Validate('http://www.example.com/', allow_fragment):
|
||||
self.valid_urls = self.valid_urls + 1
|
||||
else:
|
||||
self.invalid_urls = self.invalid_urls + 1
|
||||
#end def Count
|
||||
valid_urls = 0
|
||||
invalid_urls = 0
|
||||
|
||||
def testInputURL(self):
|
||||
""" Test one of the Input mechanisms: InputURL """
|
||||
|
||||
# Feed a couple URLs. Make sure we get an error on extra attributes.
|
||||
self.valid_urls = 0
|
||||
self.invalid_urls = 0
|
||||
error = sitemap_gen.output.num_errors
|
||||
warn = sitemap_gen.output.num_warns
|
||||
generator1 = sitemap_gen.InputURL({'href' : 'http://www.example.com/1',
|
||||
'priority' : '0.3',
|
||||
'lastmod' : '2004-11-14T01:00-07:00',
|
||||
'changefreq' : 'hourly',
|
||||
'unknownInURL' : 'attribute'})
|
||||
generator2 = sitemap_gen.InputURL({'href' : 'http://www.example.com/2',
|
||||
'priority' : '0.3',
|
||||
'lastmod' : '2004-11-14T01:00-07:00',
|
||||
'changefreq' : 'hourly'})
|
||||
generator1.ProduceURLs(self.Count)
|
||||
generator2.ProduceURLs(self.Count)
|
||||
self.assertEqual(self.valid_urls, 1)
|
||||
self.assertEqual(self.invalid_urls, 0)
|
||||
self.assertEqual(sitemap_gen.output.num_errors, error + 1)
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn)
|
||||
#end def testInputURL
|
||||
|
||||
def testInputURLList(self):
|
||||
""" Test one of the Input mechanisms: InputURLList """
|
||||
path = tempfile.mktemp()
|
||||
file = open(path, 'w')
|
||||
|
||||
try:
|
||||
# Create a temp file we can read
|
||||
testText = """
|
||||
http://www.example.com/foo/bar unknownInURLList=attribute
|
||||
http://www.example.com/foo/xxx.pdf lastmod=2003-12-31T14:05:06+00:00
|
||||
http://www.example.com/foo/yyy?x=12&y=23 changefreq=weekly priority=0.3
|
||||
"""
|
||||
file.write(testText)
|
||||
file.close()
|
||||
|
||||
# Feed in the data. Make sure we get a warning on the bad attribute.
|
||||
self.valid_urls = 0
|
||||
self.invalid_urls = 0
|
||||
warn = sitemap_gen.output.num_warns
|
||||
generator = sitemap_gen.InputURLList({'path' : path})
|
||||
generator.ProduceURLs(self.Count)
|
||||
self.assertEqual(self.valid_urls, 3)
|
||||
self.assertEqual(self.invalid_urls, 0)
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn + 1)
|
||||
|
||||
finally:
|
||||
os.unlink(path)
|
||||
#end def testInputURLList
|
||||
|
||||
def testInputDirectory(self):
|
||||
"""Test one of the Input mechanisms: InputDirectory.
|
||||
I've seen a subtle path-bug appear when going into sub-sub-directories
|
||||
that didn't under just sub-directories. So we go to the trouble to
|
||||
make a whole little directory tree to read.
|
||||
"""
|
||||
counter = URLCounter('http://www.example.com/', True, (
|
||||
'http://www.example.com/',
|
||||
'http://www.example.com/one.html',
|
||||
'http://www.example.com/two.html',
|
||||
'http://www.example.com/xyzzy/',
|
||||
'http://www.example.com/xyzzy/thr.html',
|
||||
'http://www.example.com/xyzzy/zyxxy/',
|
||||
'http://www.example.com/xyzzy/zyxxy/fiv.html',
|
||||
))
|
||||
path = tempfile.mktemp()
|
||||
subpath = os.path.join(path, 'xyzzy')
|
||||
subsubpath = os.path.join(subpath, 'zyxxy')
|
||||
|
||||
try:
|
||||
# Create some dummy empty files
|
||||
os.mkdir(path)
|
||||
os.mkdir(subpath)
|
||||
os.mkdir(subsubpath)
|
||||
path_one = os.path.join(path, 'one.html')
|
||||
path_two = os.path.join(path, 'two.html')
|
||||
path_thr = os.path.join(subpath, 'thr.html')
|
||||
path_for = os.path.join(subpath, 'default.html')
|
||||
path_fiv = os.path.join(subsubpath, 'fiv.html')
|
||||
open(path_one, 'w').close()
|
||||
open(path_two, 'w').close()
|
||||
open(path_thr, 'w').close()
|
||||
open(path_for, 'w').close()
|
||||
open(path_fiv, 'w').close()
|
||||
|
||||
# Feed in the data. There should be no warnings.
|
||||
warn = sitemap_gen.output.num_warns
|
||||
generator = sitemap_gen.InputDirectory({'path' : path,
|
||||
'url' : 'http://www.example.com/', 'default_file' : 'default.html'},
|
||||
'http://www.example.com/')
|
||||
generator.ProduceURLs(counter.Count)
|
||||
self.assertEqual(counter.Valid(), 7)
|
||||
self.assertEqual(counter.Invalid(), 0)
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn)
|
||||
|
||||
finally:
|
||||
os.unlink(path_one)
|
||||
os.unlink(path_two)
|
||||
os.unlink(path_thr)
|
||||
os.unlink(path_for)
|
||||
os.unlink(path_fiv)
|
||||
os.rmdir(subsubpath)
|
||||
os.rmdir(subpath)
|
||||
os.rmdir(path)
|
||||
#end def testInputDirectory
|
||||
|
||||
def testInputAccessLogCLF(self):
|
||||
""" Test one of the Input mechanisms: InputAccessLog (Common logfile) """
|
||||
path = tempfile.mktemp()
|
||||
file = open(path, 'w')
|
||||
|
||||
try:
|
||||
# Create a temp file we can read
|
||||
testText = '''
|
||||
msnbot.msn.com - - [15/May/2005:07:46:50 -0700] "GET /~guest/main/ HTTP/1.0" 200 5670
|
||||
221.216.237.71 - - [15/May/2005:07:59:25 -0700] "GET /~guest/bookmark/ HTTP/1.1" 200 39195
|
||||
221.216.237.71 - - [15/May/2005:07:59:27 -0700] "GET /favicon.ico HTTP/1.1" 404 217
|
||||
c-67-161-121-105.hsd1.wa.comcast.net - - [15/May/2005:11:17:23 -0700] "GET /picts/top.jpg HTTP/1.1" 200 10044
|
||||
cpe-65-24-155-46.columbus.res.rr.com - - [16/May/2005:22:53:07 -0700] "HEAD http://www.example.com/~guest HTTP/1.1" 200 0
|
||||
'''
|
||||
file.write(testText)
|
||||
file.close()
|
||||
|
||||
# Feed in the data
|
||||
self.valid_urls = 0
|
||||
self.invalid_urls = 0
|
||||
warn = sitemap_gen.output.num_warns
|
||||
generator = sitemap_gen.InputAccessLog({'path' : path})
|
||||
generator.ProduceURLs(self.Count)
|
||||
self.assertEqual(self.valid_urls, 4)
|
||||
self.assertEqual(self.invalid_urls, 0)
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn)
|
||||
|
||||
finally:
|
||||
os.unlink(path)
|
||||
#end def testInputAccessLogCLF
|
||||
|
||||
def testInputAccessLogELF(self):
|
||||
""" Test one of the Input mechanisms: InputAccessLog (Extended logfile) """
|
||||
path = tempfile.mktemp()
|
||||
file = open(path, 'w')
|
||||
|
||||
try:
|
||||
# Create a temp file we can read
|
||||
testText = '''
|
||||
#Software: Microsoft Internet Information Services 6.0
|
||||
#Version: 1.0
|
||||
#Date: 2004-03-22 09:20:36
|
||||
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-w
|
||||
in32-status
|
||||
2004-03-22 09:20:36 192.168.0.58 GET /Default.htm - 80 - 4.5.11.3 Mozilla/4.0+(compatible;+MSIE+5.5;+Windows+98) 200 0 64
|
||||
2004-03-22 09:22:58 192.168.0.58 GET /Default.htm - 80 - 24.87.160.82 Mozilla/4.0+(compatible;+MSIE+5.5;+Windows+98) 200 0 6
|
||||
4
|
||||
'''
|
||||
file.write(testText)
|
||||
file.close()
|
||||
|
||||
# Feed in the data
|
||||
self.valid_urls = 0
|
||||
self.invalid_urls = 0
|
||||
warn = sitemap_gen.output.num_warns
|
||||
generator = sitemap_gen.InputAccessLog({'path' : path})
|
||||
generator.ProduceURLs(self.Count)
|
||||
self.assertEqual(self.valid_urls, 2)
|
||||
self.assertEqual(self.invalid_urls, 0)
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn)
|
||||
|
||||
finally:
|
||||
os.unlink(path)
|
||||
#end def testInputAccessLogELF
|
||||
|
||||
def testInputSitemap(self):
|
||||
""" Test one of the Input mechanisms: InputSitemap """
|
||||
path1 = tempfile.mktemp('.xml')
|
||||
path2 = tempfile.mktemp('.xml')
|
||||
path3 = tempfile.mktemp('.xml')
|
||||
path4 = tempfile.mktemp('.xml')
|
||||
file1 = None
|
||||
file2 = None
|
||||
file3 = None
|
||||
file4 = None
|
||||
|
||||
index = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex
|
||||
xmlns="http://www.google.com/schemas/sitemap/0.84"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.google.com/schemas/sitemap/0.84
|
||||
http://www.google.com/schemas/sitemap/0.84/siteindex.xsd">
|
||||
<sitemap>
|
||||
<loc>http://www.example.com/path/to/%(PATH2)s</loc>
|
||||
<lastmod>2005-07-15T17:41:22Z</lastmod>
|
||||
</sitemap>
|
||||
<sitemap>
|
||||
<loc>http://www.example.com/path/to/%(PATH3)s</loc>
|
||||
<lastmod>2005-07-15T17:41:22Z</lastmod>
|
||||
</sitemap>
|
||||
</sitemapindex>
|
||||
'''
|
||||
content1 = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset
|
||||
xmlns="http://www.google.com/schemas/sitemap/0.84"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.google.com/schemas/sitemap/0.84
|
||||
http://www.google.com/schemas/sitemap/0.84/sitemap.xsd">
|
||||
<url>
|
||||
<loc>http://www.example.com/another/path/to/samplefile1.html</loc>
|
||||
<lastmod>2005-07-13T00:00:12Z</lastmod>
|
||||
<priority>0.5000</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://www.example.com/another/path/to/samplefile2.html</loc>
|
||||
<lastmod>2004-11-16T20:22:06Z</lastmod>
|
||||
<priority>0.5000</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
'''
|
||||
content2 = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset
|
||||
xmlns="http://www.google.com/schemas/sitemap/0.84"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.google.com/schemas/sitemap/0.84
|
||||
http://www.google.com/schemas/sitemap/0.84/sitemap.xsd">
|
||||
<url badSitemapAttr="Hello, World!">
|
||||
<loc>http://www.example.com/another/path/to/samplefile3.html</loc>
|
||||
<lastmod>2005-07-13T00:00:12Z</lastmod>
|
||||
<priority>0.5000</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://www.example.com/another/path/to/samplefile4.html</loc>
|
||||
<lastmod>2004-11-16T20:22:06Z</lastmod>
|
||||
<priority>0.5000</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
'''
|
||||
# This index is invalid because it points to another index file.
|
||||
badindex = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex
|
||||
xmlns="http://www.google.com/schemas/sitemap/0.84"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.google.com/schemas/sitemap/0.84
|
||||
http://www.google.com/schemas/sitemap/0.84/siteindex.xsd">
|
||||
<sitemap>
|
||||
<loc>http://www.example.com/path/to/%(PATH2)s</loc>
|
||||
<lastmod>2005-07-15T17:41:22Z</lastmod>
|
||||
</sitemap>
|
||||
<sitemap>
|
||||
<loc>http://www.example.com/path/to/%(PATH1)s</loc>
|
||||
<lastmod>2005-07-15T17:41:22Z</lastmod>
|
||||
</sitemap>
|
||||
</sitemapindex>
|
||||
'''
|
||||
|
||||
# Make a nice complicated set of two index files and two sitemaps.
|
||||
try:
|
||||
file1 = open(path1, 'wt')
|
||||
file2 = open(path2, 'wt')
|
||||
file3 = open(path3, 'wt')
|
||||
file4 = open(path4, 'wt')
|
||||
file1.write(index % {
|
||||
'PATH1' : os.path.basename(path1),
|
||||
'PATH2' : os.path.basename(path2),
|
||||
'PATH3' : os.path.basename(path3)})
|
||||
file2.write(content1)
|
||||
file3.write(content2)
|
||||
file4.write(badindex % {
|
||||
'PATH1' : os.path.basename(path1),
|
||||
'PATH2' : os.path.basename(path2),
|
||||
'PATH3' : os.path.basename(path3)})
|
||||
file1.close()
|
||||
file1 = None
|
||||
file2.close()
|
||||
file2 = None
|
||||
file3.close()
|
||||
file3 = None
|
||||
file4.close()
|
||||
file4 = None
|
||||
|
||||
# Feed in the good data. Make sure we get warned on the bad attribute.
|
||||
self.valid_urls = 0
|
||||
self.invalid_urls = 0
|
||||
warn = sitemap_gen.output.num_warns
|
||||
generator = sitemap_gen.InputSitemap({'path' : path1})
|
||||
generator.ProduceURLs(self.Count)
|
||||
self.assertEqual(self.valid_urls, 4)
|
||||
self.assertEqual(self.invalid_urls, 0)
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn + 1)
|
||||
|
||||
# Feed in the bad data. Should error once on the bad index and once
|
||||
# because it aborts processing the XML.
|
||||
self.valid_urls = 0
|
||||
self.invalid_urls = 0
|
||||
errors = sitemap_gen.output.num_errors
|
||||
generator = sitemap_gen.InputSitemap({'path' : path4})
|
||||
generator.ProduceURLs(self.Count)
|
||||
self.assertEqual(self.valid_urls, 2)
|
||||
self.assertEqual(self.invalid_urls, 0)
|
||||
self.assertEqual(sitemap_gen.output.num_errors, errors + 2)
|
||||
|
||||
finally:
|
||||
if file1 is not None:
|
||||
file1.close()
|
||||
if file2 is not None:
|
||||
file2.close()
|
||||
if file3 is not None:
|
||||
file3.close()
|
||||
if os.path.exists(path1):
|
||||
os.unlink(path1)
|
||||
if os.path.exists(path2):
|
||||
os.unlink(path2)
|
||||
if os.path.exists(path3):
|
||||
os.unlink(path3)
|
||||
#end def testInputSitemap
|
||||
|
||||
def testFilePathGenerator(self):
|
||||
""" Test our iteration of filenames """
|
||||
gen1 = sitemap_gen.FilePathGenerator()
|
||||
gen2 = sitemap_gen.FilePathGenerator()
|
||||
gen3 = sitemap_gen.FilePathGenerator()
|
||||
self.assert_(gen1.Preload('/tmp/bar/foo.xml'))
|
||||
self.assert_(gen2.Preload('foo.xml.gz'))
|
||||
self.assert_(gen3.Preload('/foo.gz'))
|
||||
self.assert_(not gen1.is_gzip)
|
||||
self.assert_( gen2.is_gzip)
|
||||
self.assert_( gen3.is_gzip)
|
||||
self.assertEqual(gen1.GeneratePath(0),
|
||||
os.path.normpath('/tmp/bar/foo.xml'))
|
||||
self.assertEqual(gen2.GeneratePath(1),'foo1.xml.gz')
|
||||
self.assertEqual(gen1.GeneratePath('_index.xml'),
|
||||
os.path.normpath('/tmp/bar/foo_index.xml'))
|
||||
self.assertEqual(gen1.GenerateURL('_index.xml', 'http://www.example.com/'),
|
||||
'http://www.example.com/foo_index.xml')
|
||||
self.assertEqual(gen1.GenerateURL(2, 'http://www.example.com/'),
|
||||
'http://www.example.com/foo2.xml')
|
||||
self.assertEqual(gen2.GenerateWildURL('http://www.example.com/'),
|
||||
'http://www.example.com/foo*.xml.gz')
|
||||
#end def testFilePathGenerator
|
||||
|
||||
def testSitemap(self):
|
||||
"""Test a basic config of the overall sitemap class."""
|
||||
path1 = tempfile.mktemp()
|
||||
path2 = tempfile.mktemp(".xml.gz")
|
||||
file = open(path1, 'w')
|
||||
|
||||
try:
|
||||
# Create a temp file we can read
|
||||
testText = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<site
|
||||
base_url="http://www.example.com/"
|
||||
store_into="%(OUTPUTFILENAME)s"
|
||||
default_encoding="UTF-8"
|
||||
verbose="3"
|
||||
>
|
||||
<url href="http://www.example.com/.htaccess" />
|
||||
<url href="http://www.example.com/foo/bar.html" />
|
||||
<url href="http://www.example.com/foo/bar.gif" />
|
||||
<url href="http://www.example.com/foo/bar.html" />
|
||||
<url href="http://www.example.com/percent%%%%percent.html" />
|
||||
<url href="http://www.example.com/ümlat.html" />
|
||||
<filter action="drop" type="regexp" pattern="/\.[^/]*$" />
|
||||
</site>
|
||||
'''
|
||||
file.write(testText % {'OUTPUTFILENAME' : path2})
|
||||
file.close()
|
||||
|
||||
# Bring up the engine
|
||||
warn = sitemap_gen.output.num_warns
|
||||
error = sitemap_gen.output.num_errors
|
||||
sitemap = sitemap_gen.CreateSitemapFromFile(path1, True)
|
||||
self.assert_(sitemap)
|
||||
sitemap.Generate()
|
||||
self.assertEqual(sitemap_gen.output.num_warns, warn)
|
||||
self.assertEqual(sitemap_gen.output.num_errors, error)
|
||||
|
||||
# Verify we got readable XML out of it
|
||||
file = gzip.open(path2, mode='rb')
|
||||
result = file.read()
|
||||
file.close()
|
||||
dom = xml.dom.minidom.parseString(result)
|
||||
self.assertEqual(len(dom.getElementsByTagName('url')), 4)
|
||||
self.assert_(result.find('http://www.example.com/foo/bar.html') > 0)
|
||||
self.assert_(result.find('http://www.example.com/foo/bar.gif') > 0)
|
||||
self.assert_(result.find('%25%25') > 0)
|
||||
self.assert_(result.find('%C3%BC') > 0)
|
||||
finally:
|
||||
if os.path.exists(path2):
|
||||
os.unlink(path2)
|
||||
os.unlink(path1)
|
||||
#end def testSitemap
|
||||
|
||||
#end class TestSiteMap
|
||||
|
||||
#
|
||||
# __main__
|
||||
#
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -1,80 +0,0 @@
|
|||
#!/bin/sh
|
||||
#| -*- scheme -*-
|
||||
exec "$PLTHOME/bin/gracket" "$0"
|
||||
|#
|
||||
|
||||
#lang racket/gui
|
||||
|
||||
;; save the original error port to send messages
|
||||
(define stderr (current-error-port))
|
||||
(define (die fmt . args)
|
||||
(apply fprintf stderr fmt args)
|
||||
(newline stderr)
|
||||
(exit 1))
|
||||
|
||||
(define (cleanup)
|
||||
(when (directory-exists? (find-system-path 'pref-dir))
|
||||
(delete-directory/files (find-system-path 'pref-dir))))
|
||||
|
||||
(define (my-handler e)
|
||||
(cleanup)
|
||||
(die "uncaught exception: ~a\n" (if (exn? e) (exn-message e) e)))
|
||||
|
||||
(define-values (in out) (make-pipe))
|
||||
((compose void thread)
|
||||
(lambda ()
|
||||
(let* ([bytes (make-bytes 1000)]
|
||||
[len/eof (sync (read-bytes-avail!-evt bytes in))])
|
||||
(die "text printed to stdout/stderr:\n~a\n"
|
||||
(if (eof-object? len/eof) len/eof (subbytes bytes 0 len/eof))))))
|
||||
|
||||
(uncaught-exception-handler my-handler)
|
||||
(current-output-port out)
|
||||
(current-error-port out)
|
||||
|
||||
;; must create eventspace after setting parameters, so its thread
|
||||
;; inherits the new settings
|
||||
(define es (make-eventspace))
|
||||
|
||||
(current-eventspace es)
|
||||
(void (thread (lambda () (sleep 120) (die "timeout!"))))
|
||||
|
||||
;; make sure the preferences are such that we don't get the welcome screen
|
||||
(cleanup)
|
||||
(make-directory (find-system-path 'pref-dir))
|
||||
(with-output-to-file (find-system-path 'pref-file) #:exists 'truncate
|
||||
(lambda ()
|
||||
(printf "~s\n" `((plt:framework-prefs
|
||||
((drracket:last-version ,(version))
|
||||
(drracket:last-language english)))))))
|
||||
|
||||
;; start drracket, get interface for testing its windows
|
||||
(define <%> #f)
|
||||
(queue-callback (lambda ()
|
||||
(dynamic-require 'drracket #f)
|
||||
(set! <%> (dynamic-require 'drracket/tool-lib
|
||||
'drracket:unit:frame<%>))))
|
||||
|
||||
(define (is-drracket-frame? win) (and <%> (is-a? win <%>)))
|
||||
|
||||
;; wait for the drracket window to appear
|
||||
(define (window-title w) (send w get-label))
|
||||
(let loop ()
|
||||
(sleep 1/100)
|
||||
(let ([wins (get-top-level-windows)])
|
||||
(cond
|
||||
;; wait to have windows
|
||||
[(null? wins) (loop)]
|
||||
;; that are all drracket frames
|
||||
[(not (andmap is-drracket-frame? wins)) (loop)]
|
||||
[(pair? (cdr wins))
|
||||
(die "too many windows popped up: ~s" (map window-title wins))]
|
||||
[(regexp-match #rx"^Untitled( - DrRacket)?$" (window-title (car wins)))
|
||||
(fprintf stderr "got a good window: ~a\n" (window-title (car wins)))]
|
||||
[else (die "bad window popped up: ~s" (window-title (car wins)))])))
|
||||
|
||||
;; handle some events
|
||||
(let loop ([n 20]) (unless (zero? n) (yield) (loop (sub1 n))))
|
||||
|
||||
;; queue a low priority callback to exit sucessfully
|
||||
(queue-callback (lambda () (cleanup) (exit 0)) #f)
|
|
@ -1,61 +0,0 @@
|
|||
#!/bin/sh
|
||||
#| -*- scheme -*-
|
||||
tmp="/tmp/path-compare-$$"
|
||||
if [ -x "$PLTHOME/bin/racket" ]; then
|
||||
"$PLTHOME/bin/racket" -r "$0" "$@"
|
||||
else
|
||||
"racket" -r "$0" "$@"
|
||||
fi > "$tmp" || exit 1
|
||||
cd "`dirname \"$0\"`"
|
||||
if diff "paths-configure-snapshot" "$tmp"; then
|
||||
echo "PATHS OK"; rm "$tmp"; exit 0
|
||||
else echo "*** PATHS DATA MISMATCH (see $tmp) ***"; exit 1
|
||||
fi
|
||||
|#
|
||||
|
||||
;; Extract path information from the configure script, so it can be compared
|
||||
;; to a snapshot and generate an error each time things change
|
||||
|
||||
(define configure-path
|
||||
(simplify-path
|
||||
(build-path
|
||||
;; (find-executable-path
|
||||
;; (find-system-path 'exec-file) (find-system-path 'collects-dir) #t)
|
||||
(find-system-path 'exec-file)
|
||||
'up 'up "src" "configure")))
|
||||
(unless (file-exists? configure-path)
|
||||
(error "Cannot find `configure':" configure-path))
|
||||
|
||||
(define current-match (make-parameter #f))
|
||||
(define (match? . bytess)
|
||||
(cond [(regexp-match (byte-regexp (apply bytes-append bytess))
|
||||
(current-input-port))
|
||||
=> (lambda (m) (current-match (car m)) #t)]
|
||||
[else #f]))
|
||||
(define (show-match)
|
||||
(write-bytes (current-match)))
|
||||
|
||||
(with-input-from-file configure-path
|
||||
(lambda ()
|
||||
(if (match? #"\n# Installation directory options.\n"
|
||||
#"(?:#[^\n]*\n)+"
|
||||
#"(?:[a-z]+=[^\n]+\n)+"
|
||||
#"\n")
|
||||
(show-match)
|
||||
(error "Did not find first block"))
|
||||
(if (match? #"\n#+ Install targets #+\n\n"
|
||||
#"unixstyle=no\n"
|
||||
#"if (?:[^\n]+\n)+fi\n\n"
|
||||
#"MAKE_COPYTREE=no\n"
|
||||
#"if [^\n]+\n"
|
||||
#"(?: +[^\n]+\n)+"
|
||||
#"else\n"
|
||||
#"(?: +[^\n]+\n)+"
|
||||
#"fi\n\n")
|
||||
(show-match)
|
||||
(error "Did not find second block"))
|
||||
(if (match? #"\n +echo \">>> Installation targets:\"\n"
|
||||
#"(?: +echo [^\n]+\n)+")
|
||||
(show-match)
|
||||
(error "Did not find third block"))))
|
||||
(exit)
|
|
@ -1,109 +0,0 @@
|
|||
|
||||
# Installation directory options.
|
||||
# These are left unexpanded so users can "make install exec_prefix=/foo"
|
||||
# and all the variables that are supposed to be based on exec_prefix
|
||||
# by default will actually change.
|
||||
# Use braces instead of parens because sh, perl, etc. also accept them.
|
||||
# (The list follows the same order as the GNU Coding Standards.)
|
||||
bindir='${exec_prefix}/bin'
|
||||
sbindir='${exec_prefix}/sbin'
|
||||
libexecdir='${exec_prefix}/libexec'
|
||||
datarootdir='${prefix}/share'
|
||||
datadir='${datarootdir}'
|
||||
sysconfdir='${prefix}/etc'
|
||||
sharedstatedir='${prefix}/com'
|
||||
localstatedir='${prefix}/var'
|
||||
includedir='${prefix}/include'
|
||||
oldincludedir='/usr/include'
|
||||
docdir='${datarootdir}/doc/${PACKAGE}'
|
||||
infodir='${datarootdir}/info'
|
||||
htmldir='${docdir}'
|
||||
dvidir='${docdir}'
|
||||
pdfdir='${docdir}'
|
||||
psdir='${docdir}'
|
||||
libdir='${exec_prefix}/lib'
|
||||
localedir='${datarootdir}/locale'
|
||||
mandir='${datarootdir}/man'
|
||||
|
||||
|
||||
############## Install targets ################
|
||||
|
||||
unixstyle=no
|
||||
if test "${prefix}" != "NONE" ; then
|
||||
if test "${enable_origtree}" != "yes" ; then
|
||||
unixstyle=yes
|
||||
fi
|
||||
fi
|
||||
if test "${exec_prefix}" != "NONE" ; then
|
||||
unixstyle=yes
|
||||
fi
|
||||
if test "${bindir}" != '${exec_prefix}/bin' ; then
|
||||
unixstyle=yes
|
||||
fi
|
||||
if test "${datadir}" != '${prefix}/share' ; then
|
||||
# Newer autoconf uses datarootdir:
|
||||
if test "${datadir}" = '${datarootdir}' ; then
|
||||
if test "${datarootdir}" != '${prefix}/share' ; then
|
||||
unixstyle=yes
|
||||
fi
|
||||
else
|
||||
unixstyle=yes
|
||||
fi
|
||||
fi
|
||||
if test "${libdir}" != '${exec_prefix}/lib' ; then
|
||||
unixstyle=yes
|
||||
fi
|
||||
if test "${includedir}" != '${prefix}/include' ; then
|
||||
unixstyle=yes
|
||||
fi
|
||||
if test "${mandir}" != '${prefix}/man' ; then
|
||||
if test "${mandir}" = '${datarootdir}/man' ; then
|
||||
if test "${datarootdir}" != '${prefix}/share' ; then
|
||||
unixstyle=yes
|
||||
fi
|
||||
else
|
||||
unixstyle=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
MAKE_COPYTREE=no
|
||||
if test "${unixstyle}" = "no" ; then
|
||||
if test "${prefix}" = "NONE" ; then
|
||||
inplacebuild=yes
|
||||
prefix=`cd "${srcdir}/.." && pwd`
|
||||
else
|
||||
MAKE_COPYTREE=copytree
|
||||
fi
|
||||
bindir='${prefix}/bin'
|
||||
libpltdir='${prefix}/lib'
|
||||
collectsdir='${prefix}/collects'
|
||||
includepltdir='${prefix}/include'
|
||||
docdir='${prefix}/doc'
|
||||
mandir='${prefix}/man'
|
||||
COLLECTS_PATH="../collects"
|
||||
INSTALL_ORIG_TREE=yes
|
||||
else
|
||||
if test "${prefix}" = "NONE" ; then
|
||||
# Set prefix explicitly so we can use it during configure
|
||||
prefix="${ac_default_prefix}"
|
||||
fi
|
||||
libpltdir="${libdir}/racket"
|
||||
collectsdir="${libdir}/racket/collects"
|
||||
includepltdir="${includedir}/racket"
|
||||
docdir="${datadir}/doc/racket"
|
||||
MAKE_COPYTREE=copytree
|
||||
COLLECTS_PATH='${collectsdir}'
|
||||
INSTALL_ORIG_TREE=no
|
||||
fi
|
||||
|
||||
|
||||
echo ">>> Installation targets:"
|
||||
echo " executables : ${bindir}/..."
|
||||
echo " Racket code : ${collectsdir}/..."
|
||||
echo " core docs : ${docdir}/..."
|
||||
echo " C libraries : ${libdir}/..."
|
||||
echo " C headers : ${includepltdir}/..."
|
||||
echo " extra C objs : ${libpltdir}/..."
|
||||
echo " man pages : ${mandir}/..."
|
||||
echo " where prefix = ${prefix}"
|
||||
echo " and datarootdir = ${datarootdir}"
|
|
@ -1,47 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
awk -- '
|
||||
/^expand_path_var()/ { showing = 1; }
|
||||
{ if (showing) print; }
|
||||
/^}/ { showing = 0; }
|
||||
' "`dirname \"$0\"/`/installer-header" > "/tmp/test-$$"
|
||||
. "/tmp/test-$$"
|
||||
rm "/tmp/test-$$"
|
||||
|
||||
test() {
|
||||
foo="$1"
|
||||
expand_path_var foo
|
||||
if [ ! "x$foo" = "x$2" ]; then
|
||||
echo "fail: $1 -> $foo; expected $2" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
test 'blah' "blah"
|
||||
test 'blah blah' "blah blah"
|
||||
test 'blah blah' "blah blah"
|
||||
test 'blah=blah' "blah=blah"
|
||||
test 'x=1 y=2 z=3' "x=1 y=2 z=3"
|
||||
test '$HOME' "$HOME"
|
||||
test '$HOME/foo' "$HOME/foo"
|
||||
test '$HOME/ foo' "$HOME/ foo"
|
||||
test '$HOME / foo' "$HOME / foo"
|
||||
test '~' "$HOME"
|
||||
test '~/' "$HOME/"
|
||||
test '~/x' "$HOME/x"
|
||||
test '~/x/y' "$HOME/x/y"
|
||||
test '~/x /y' "$HOME/x /y"
|
||||
test '~/ x / y ' "$HOME/ x / y "
|
||||
test '~/ ' "$HOME/ "
|
||||
test '~ ' "~ "
|
||||
test '~eli' "$HOME"
|
||||
test '~eli ' "~eli "
|
||||
test '~e li' "~e li"
|
||||
test '~ eli' "~ eli"
|
||||
test '~eli /x' "~eli /x"
|
||||
test '~root/x' "/root/x"
|
||||
test '~bleh' "~bleh"
|
||||
test '~bleh ' "~bleh "
|
||||
test '~/x y' "$HOME/x y"
|
||||
test '~/x;pwd' "$HOME/x;pwd"
|
||||
echo "All tests passed."
|
|
@ -1,466 +0,0 @@
|
|||
#!/bin/sh
|
||||
#| -*- scheme -*-
|
||||
exec racket "$0" "$@"
|
||||
|#
|
||||
|
||||
#lang at-exp racket/base
|
||||
|
||||
(require racket/list racket/file racket/match racket/system)
|
||||
|
||||
(define (err fmt . args)
|
||||
(raise-user-error (format "Error: ~a" (apply format fmt args))))
|
||||
|
||||
(define testdir "/tmp/racket-installer-test")
|
||||
(define installer
|
||||
(match (current-command-line-arguments)
|
||||
[(vector installer) installer]
|
||||
[(vector _ ...) (err "usage: test-installer <installer-file-name>")]))
|
||||
|
||||
(define (exe name [just-path? #f])
|
||||
(define path (or (find-executable-path name)
|
||||
(err "no `~a' executable found" name)))
|
||||
(λ args (unless (apply system* path args)
|
||||
(err "`~a' signaled an error" name))))
|
||||
|
||||
(define expect-exe (exe "expect"))
|
||||
(define sync-exe (exe "sync"))
|
||||
|
||||
(unless (file-exists? installer) (err "missing installer at: ~a" installer))
|
||||
(when (directory-exists? testdir) (err "test directory exists: ~a" testdir))
|
||||
(make-directory testdir)
|
||||
(current-directory testdir)
|
||||
;; plain interaction, identifiable prompts, safe-for-play home
|
||||
(void (putenv "TERM" "dumb") (putenv "PS1" "sh> ") (putenv "HOME" testdir))
|
||||
|
||||
(define (transcript)
|
||||
;; the test transcript text:
|
||||
;; - text is matched against the process output (anchored)
|
||||
;; - `i' is for user input to send
|
||||
;; - `r' is for a regexp
|
||||
;; - `s' is a nested list to be spliced in
|
||||
;; - `N' is short for @r{(?:-?[0-9.]+)?}
|
||||
;; - `...' makes the next match unanchored (so it's similar to a non-greedy
|
||||
;; ".*" regexp)
|
||||
(define (i . xs) `(i . ,xs))
|
||||
(define (r . xs) `(r . ,xs))
|
||||
(define (s . xs) `(s . ,xs))
|
||||
(define break 'break)
|
||||
(define N @r{(?:-?[0-9.]+)?})
|
||||
(define ... '...)
|
||||
(define not-recommended
|
||||
(let ([s (string-append
|
||||
"*** This is a nightly build: such a unix-style distribution"
|
||||
" is *not*\n"
|
||||
"*** recommended because it cannot be used to install multiple"
|
||||
" versions.\n")])
|
||||
(format "(?:~a)?" (regexp-quote s))))
|
||||
@list{
|
||||
@; the first few puzzling interactions are testing that we generate the
|
||||
@; right expect code -- which requires regexp and $-quoting.
|
||||
sh> @i{echo "blah"}
|
||||
blah
|
||||
sh> @i{echo 'blah'}
|
||||
blah
|
||||
sh> @i{x=123}
|
||||
sh> @i{echo "][@"}{"blah*$x*"}
|
||||
][@"}{"blah*123*
|
||||
sh> @i{echo '[]{}blah*$x*'}
|
||||
[]{}blah*$x*
|
||||
sh> @i{pwd}
|
||||
@testdir
|
||||
@; utilities
|
||||
sh> @i{LS() { ls --width=72 -mF "$@"@""@";" }}
|
||||
@; proper testing begins here
|
||||
sh> @i{sh @installer}
|
||||
This program will extract and install Racket v@|N|.
|
||||
@||
|
||||
Note: the required diskspace for this installation is @|N|M.
|
||||
@||
|
||||
Do you want a Unix-style distribution?
|
||||
In this distribution mode files go into different directories according
|
||||
to Unix conventions. A "racket-uninstall" script will be generated
|
||||
to be used when you want to remove the installation. If you say 'no',
|
||||
the whole Racket directory is kept in a single installation directory
|
||||
(movable and erasable), possibly with external links into it -- this is
|
||||
often more convenient, especially if you want to install multiple
|
||||
versions or keep it in your home directory.
|
||||
@r{@not-recommended}@;
|
||||
Enter yes/no (default: no) > @i{bleh}
|
||||
Enter yes/no (default: no) > @i{foo}
|
||||
Enter yes/no (default: no) > @i{}
|
||||
@||
|
||||
Where do you want to install the "racket@N" directory tree?
|
||||
1 - /usr/racket@N [default]
|
||||
2 - /usr/local/racket@N
|
||||
3 - ~/racket@N (@|testdir|/racket@N)
|
||||
4 - ./racket@N (here)
|
||||
Or enter a different "racket" directory to install in.
|
||||
> @i{4}
|
||||
@||
|
||||
Checking the integrity of the binary archive... ok.
|
||||
Unpacking into "@|testdir|/racket@N" (Ctrl+C to abort)...
|
||||
Done.
|
||||
@||
|
||||
If you want to install new system links within the "bin" and
|
||||
"man" subdirectories of a common directory prefix (for example,
|
||||
"/usr/local") then enter the prefix of an existing directory
|
||||
that you want to use. This might overwrite existing symlinks,
|
||||
but not files.
|
||||
(default: skip links) > @i{}
|
||||
@||
|
||||
Installation complete.
|
||||
sh> @i{LS}
|
||||
racket@|N|/
|
||||
sh> @i{LS racket*}
|
||||
README, bin/, collects/, doc/, include/, lib/, man/
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{No}
|
||||
@...
|
||||
> @i{.}
|
||||
@||
|
||||
Checking the integrity of the binary archive... ok.
|
||||
"@|testdir|/racket@N" exists, delete? @i{n}
|
||||
Aborting installation.
|
||||
sh> @i{LS racket*}
|
||||
README, bin/, collects/, doc/, include/, lib/, man/
|
||||
sh> @i{chmod 000 racket*}
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{No}
|
||||
@...
|
||||
> @i{./}
|
||||
@||
|
||||
Checking the integrity of the binary archive... ok.
|
||||
"@|testdir|/racket@N" exists, delete? @i{y}
|
||||
Deleting old "@|testdir|/racket@N"... @;
|
||||
/usr/bin/rm: cannot remove ‘@|testdir|/racket@|N|’: @;
|
||||
Permission denied
|
||||
Error: could not delete "@|testdir|/racket@N".
|
||||
sh> @i{chmod 755 racket*}
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{No}
|
||||
@...
|
||||
> @i{.}
|
||||
@||
|
||||
Checking the integrity of the binary archive... ok.
|
||||
"@|testdir|/racket@N" exists, delete? @i{y}
|
||||
Deleting old "@|testdir|/racket@N"... done.
|
||||
@...
|
||||
(default: skip links) > @i{.}
|
||||
"@|testdir|/bin" does not exist, skipping.
|
||||
"@|testdir|/share/man/man1" does not exist, skipping.
|
||||
@||
|
||||
Installation complete.
|
||||
sh> @i{mkdir bin}
|
||||
sh> @i{touch R bin/gracket}
|
||||
sh> @i{export TGT=R}
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{}
|
||||
@...
|
||||
> @i{$TGT}
|
||||
@||
|
||||
Checking the integrity of the binary archive... ok.
|
||||
"R" exists (as a file), delete? @i{y}
|
||||
Deleting old "R"... done.
|
||||
Unpacking into "@|testdir|/R" (Ctrl+C to abort)...
|
||||
Done.
|
||||
@...
|
||||
(default: skip links) > @i{.}
|
||||
Installing links in "@|testdir|/bin"...
|
||||
drracket, gracket skipped (non-link exists), gracket-text, mred, @;
|
||||
mred-text, mzc, mzpp, mzscheme, mztext, pdf-slatex, plt-games, @;
|
||||
plt-help, plt-r5rs, plt-r6rs, plt-web-server, racket, raco, scribble, @;
|
||||
setup-plt, slatex, slideshow, swindle
|
||||
done.
|
||||
"@|testdir|/share/man/man1" does not exist, skipping.
|
||||
@||
|
||||
Installation complete.
|
||||
sh> @i{LS .}
|
||||
R/, bin/, racket@|N|/
|
||||
sh> @i{LS R}
|
||||
README, bin/, collects/, doc/, include/, lib/, man/
|
||||
sh> @i{LS bin}
|
||||
@s|{drracket@, gracket, gracket-text@, mred@, mred-text@, mzc@, mzpp@,
|
||||
mzscheme@, mztext@, pdf-slatex@, plt-games@, plt-help@, plt-r5rs@,
|
||||
plt-r6rs@, plt-web-server@, racket@, raco@, scribble@, setup-plt@,
|
||||
slatex@, slideshow@, swindle@}|
|
||||
sh> @i{LS -l bin/ra*}
|
||||
lrwxrwxrwx. @... bin/racket -> @|testdir|/R/bin/racket*
|
||||
lrwxrwxrwx. @... bin/raco -> @|testdir|/R/bin/raco*
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{}
|
||||
@...
|
||||
> @i{$TGT`echo 1`}
|
||||
@||
|
||||
Checking the integrity of the binary archive... ok.
|
||||
Unpacking into "@|testdir|/R1" (Ctrl+C to abort)...
|
||||
@break
|
||||
@; HACK! BAD TEST!
|
||||
@; This test fails sometimes, when `tar' happens to be the first to break,
|
||||
@; leading to an unpacking error followed by the file cleanup followed by
|
||||
@; the "aborting" errors and no cleanup (since it's already done). The
|
||||
@; test can be modified to try either pattern but it'd be better to find
|
||||
@; a way to make the output more predictable -- somehow kill the tar
|
||||
@; process before it errors, and more generally, make it kill any child
|
||||
@; processes.
|
||||
Error: Aborting...
|
||||
(Removing installation files in @|testdir|/R1)
|
||||
sh> @i{LS}
|
||||
R/, bin/, racket@|N|/
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{}
|
||||
@...
|
||||
> @i{mmm}
|
||||
@...
|
||||
Unpacking into "@|testdir|/mmm" (Ctrl+C to abort)...
|
||||
Done.
|
||||
@...
|
||||
(default: skip links) > @break
|
||||
Error: Aborting...
|
||||
sh> @i{LS}
|
||||
R/, bin/, mmm/, racket@|N|/
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{}
|
||||
@...
|
||||
> @i{`pwd`}
|
||||
@...
|
||||
"@testdir" is where you ran the installer from, delete? @i{y}
|
||||
Deleting old "@testdir"... done.
|
||||
*** Note: your original directory was deleted, so you will need
|
||||
*** to 'cd' back into it when the installer is done, otherwise
|
||||
*** it will look like you have an empty directory.
|
||||
Unpacking into "@testdir" (Ctrl+C to abort)...
|
||||
Done.
|
||||
@...
|
||||
(default: skip links) > @i{/usr/local}
|
||||
"/usr/local" is not writable, skipping links.
|
||||
@||
|
||||
Installation complete.
|
||||
sh> @i{LS}
|
||||
sh> @i{cd /}
|
||||
sh> @i{cd @testdir}
|
||||
sh> @i{LS}
|
||||
README, bin/, collects/, doc/, include/, lib/, man/
|
||||
sh> @i{rm -rf [a-zR]*}
|
||||
sh> @i{LS}
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Do you want a Unix-style distribution?
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{bleh}
|
||||
Enter yes/no (default: no) > @i{yes}
|
||||
@||
|
||||
Where do you want to base your installation of Racket v@|N|?
|
||||
(If you've done such an installation in the past, either
|
||||
enter the same directory, or run 'racket-uninstall' manually.)
|
||||
1 - /usr/... [default]
|
||||
2 - /usr/local/...
|
||||
3 - ~/... (@|testdir|/...)
|
||||
4 - ./... (here)
|
||||
Or enter a different directory prefix to install in.
|
||||
> @i{}
|
||||
Error: The entered base directory is not writable: /usr
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{y}
|
||||
@...
|
||||
> @i{2}
|
||||
Error: The entered base directory is not writable: /usr/local
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{y}
|
||||
@...
|
||||
> @i{3}
|
||||
@||
|
||||
Target Directories:
|
||||
[e] Executables @|testdir|/bin (will be created)
|
||||
[r] Racket Code @|testdir|/lib/racket@|N|/collects (will be created)
|
||||
[d] Core Docs @|testdir|/share/racket@|N|/doc (will be created)
|
||||
[l] C Libraries @|testdir|/lib (will be created)
|
||||
[h] C headers @|testdir|/include/racket@|N| (will be created)
|
||||
[o] Extra C Objs @|testdir|/lib/racket@|N| (will be created)
|
||||
[m] Man Pages @|testdir|/share/man (will be created)
|
||||
Enter a letter to change an entry, or enter to continue.
|
||||
> @i{z}
|
||||
> @i{Q}
|
||||
> @i{}
|
||||
@||
|
||||
Checking the integrity of the binary archive... ok.
|
||||
Unpacking into "@|testdir|/racket@|N|-tmp-install" (Ctrl+C to abort)...
|
||||
Done.
|
||||
Moving bin -> @|testdir|/bin
|
||||
Moving collects -> @|testdir|/lib/racket@|N|/collects
|
||||
Moving doc -> @|testdir|/share/racket@|N|/doc
|
||||
Moving include -> @|testdir|/include/racket@|N|
|
||||
Moving lib -> @|testdir|/lib/racket@|N|
|
||||
Moving man -> @|testdir|/share/man
|
||||
Moving README -> @|testdir|/share/racket@|N|/doc/README
|
||||
Writing uninstaller at: @|testdir|/bin/racket-uninstall...
|
||||
Rewriting configuration file at: @|testdir|/lib/racket@|N|/@;
|
||||
collects/config/config.rkt...
|
||||
Recompiling to @|testdir|/lib/racket@|N|/@;
|
||||
collects/config/compiled/config_rkt.zo...
|
||||
@||
|
||||
Installation complete.
|
||||
sh> @i{LS}
|
||||
bin/, include/, lib/, share/
|
||||
sh> @i{LS bin}
|
||||
drracket*, gracket*, gracket-text*, mred*, mred-text*, mzc*, mzpp*,
|
||||
mzscheme*, mztext*, pdf-slatex*, plt-games*, plt-help*, plt-r5rs*,
|
||||
plt-r6rs*, plt-web-server*, racket*, racket-uninstall*, raco*,
|
||||
scribble*, setup-plt*, slatex*, slideshow*, swindle*
|
||||
sh> @i{LS include && LS lib && LS share}
|
||||
racket@|N|/
|
||||
racket@|N|/
|
||||
man/, racket@|N|/
|
||||
sh> @i{LS include/r*}
|
||||
escheme.h, ext.exp, mzconfig.h, mzscheme3m.exp, scheme.h, schemef.h,
|
||||
schemegc2.h, schemex.h, schemexm.h, schexn.h, schgc2obj.h, schthread.h,
|
||||
schvers.h, sconfig.h, stypes.h, uconfig.h
|
||||
sh> @i{LS lib/r*}
|
||||
buildinfo, collects/, mzdyn3m.o, starter*
|
||||
sh> @i{LS share/r* && LS share/r*/doc}
|
||||
doc/
|
||||
README, @|...|xrepl/
|
||||
sh> @i{LS share/man && LS share/man/man1}
|
||||
man1/
|
||||
drracket.1, gracket.1, mred.1, mzc.1, mzscheme.1, plt-help.1, racket.1,
|
||||
raco.1, setup-plt.1
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{y}
|
||||
@...
|
||||
> @i{meh}
|
||||
Base directory does not exist: meh
|
||||
should I create it? (default: yes) @i{n}
|
||||
Aborting installation.
|
||||
sh> @i{touch m}
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{y}
|
||||
@...
|
||||
> @i{4}
|
||||
@||
|
||||
Target Directories:
|
||||
[e] Executables @|testdir|/bin (exists)
|
||||
[r] Racket Code @|testdir|/lib/racket@|N|/collects (exists)
|
||||
[d] Core Docs @|testdir|/share/racket@|N|/doc (exists)
|
||||
[l] C Libraries @|testdir|/lib (exists)
|
||||
[h] C headers @|testdir|/include/racket@|N| (exists)
|
||||
[o] Extra C Objs @|testdir|/lib/racket@|N| (exists)
|
||||
[m] Man Pages @|testdir|/share/man (exists)
|
||||
Enter a letter to change an entry, or enter to continue.
|
||||
> @i{m}
|
||||
New directory (absolute or relative to @testdir): @i{m}
|
||||
@||
|
||||
Target Directories:
|
||||
[e] Executables @|testdir|/bin (exists)
|
||||
[r] Racket Code @|testdir|/lib/racket@|N|/collects (exists)
|
||||
[d] Core Docs @|testdir|/share/racket@|N|/doc (exists)
|
||||
[l] C Libraries @|testdir|/lib (exists)
|
||||
[h] C headers @|testdir|/include/racket@|N| (exists)
|
||||
[o] Extra C Objs @|testdir|/lib/racket@|N| (exists)
|
||||
[m] Man Pages @|testdir|/m (error: not a directory!)
|
||||
Enter a letter to change an entry, or enter to continue.
|
||||
> @i{}
|
||||
*** Please fix erroneous paths to proceed
|
||||
@...
|
||||
Enter a letter to change an entry, or enter to continue.
|
||||
> @i{m}
|
||||
New directory (absolute or relative to @testdir): @i{man}
|
||||
@||
|
||||
Target Directories:
|
||||
[e] Executables @|testdir|/bin (exists)
|
||||
[r] Racket Code @|testdir|/lib/racket@|N|/collects (exists)
|
||||
[d] Core Docs @|testdir|/share/racket@|N|/doc (exists)
|
||||
[l] C Libraries @|testdir|/lib (exists)
|
||||
[h] C headers @|testdir|/include/racket@|N| (exists)
|
||||
[o] Extra C Objs @|testdir|/lib/racket@|N| (exists)
|
||||
[m] Man Pages @|testdir|/man (will be created)
|
||||
Enter a letter to change an entry, or enter to continue.
|
||||
> @i{}
|
||||
@||
|
||||
A previous Racket uninstaller is found at
|
||||
"@|testdir|/bin/racket-uninstall",
|
||||
should I run it? (default: yes) @i{}
|
||||
running uninstaller... done.
|
||||
@||
|
||||
Checking the integrity of the binary archive... ok.
|
||||
@...
|
||||
Installation complete.
|
||||
sh> @i{LS}
|
||||
bin/, include/, lib/, m, man/, share/
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{y}
|
||||
@...
|
||||
> @i{4}
|
||||
@...
|
||||
> @i{}
|
||||
@||
|
||||
A previous Racket uninstaller is found at
|
||||
"@|testdir|/bin/racket-uninstall",
|
||||
should I run it? (default: yes) @i{n}
|
||||
Aborting installation.
|
||||
sh> @i{rm -rf share}
|
||||
sh> @i{sh @installer}
|
||||
@...
|
||||
Enter yes/no (default: no) > @i{y}
|
||||
@...
|
||||
> @i{4}
|
||||
@...
|
||||
[m] Man Pages @|testdir|/man (exists)
|
||||
Enter a letter to change an entry, or enter to continue.
|
||||
> @break
|
||||
Error: Aborting...
|
||||
sh> @i{LS}
|
||||
bin/, include/, lib/, m, man/
|
||||
sh> @i{exit}
|
||||
@||})
|
||||
|
||||
(define (make-expect-script)
|
||||
(printf "spawn sh\nproc abort {} { puts \"timeout!\\n\"; exit 1 }\n")
|
||||
(printf "set timeout 60\n")
|
||||
(define (tclq str)
|
||||
;; tcl uses $ and [] for variable & function call interpolation, and "}{"
|
||||
;; can confuse it; quote all of these
|
||||
(regexp-replace* "[][{}$]" (format "~s" str) "\\\\&"))
|
||||
(define (expect strs anchored?)
|
||||
(unless (null? strs)
|
||||
(define str (if (string? strs) strs (apply string-append strs)))
|
||||
(let ([str (regexp-replace* "\r?\n" str "\r\n")])
|
||||
(printf "expect {\n timeout abort\n -re ~a\n}\n"
|
||||
(tclq (if anchored? (string-append "^" str) str))))))
|
||||
(define (send strs)
|
||||
(define str (if (string? strs) strs (apply string-append strs)))
|
||||
(printf "send -- ~a\n" (tclq (string-append str "\n"))))
|
||||
(let loop ([strs '()] [xs (transcript)] [anchored? #t])
|
||||
(define (do-expect) (expect (reverse strs) anchored?))
|
||||
(if (null? xs)
|
||||
(do-expect)
|
||||
(match (car xs)
|
||||
['... (do-expect) (loop '() (cdr xs) #f)]
|
||||
[(? string? x) (loop (cons (regexp-quote x) strs) (cdr xs) anchored?)]
|
||||
[`(s . ,sxs) (loop strs (append sxs (cdr xs)) anchored?)]
|
||||
[`(r . ,rxs) (loop (append (reverse rxs) strs) (cdr xs) anchored?)]
|
||||
[`(i . ,inps) (do-expect) (send inps)
|
||||
(loop (map regexp-quote (reverse inps)) (cdr xs) #t)]
|
||||
['break (do-expect) (printf "send \"\\03\"\n")
|
||||
(loop '("\\^C") (cdr xs) #t)]
|
||||
[x (err "bad item in transcript: ~s" (car xs))])))
|
||||
(printf "expect eof\n"))
|
||||
|
||||
(with-output-to-file "/tmp/racket-installer-expect-script" make-expect-script)
|
||||
(sync-exe) ; we'll shuffle a lot of bytes, be prepared
|
||||
(expect-exe "/tmp/racket-installer-expect-script")
|
||||
|
||||
(delete-directory/files testdir)
|
||||
(delete-file "/tmp/racket-installer-expect-script")
|
||||
|
||||
(printf "\n--> All tests passed.\n")
|
|
@ -1,107 +0,0 @@
|
|||
#!/bin/sh
|
||||
#| -*- scheme -*-
|
||||
exec racket -um "$0" "$@"
|
||||
|#
|
||||
|
||||
#lang racket/base
|
||||
(require version/utils racket/file)
|
||||
|
||||
(define (patches)
|
||||
;; no grouping parens in regexps
|
||||
(let* ([parts# (length (regexp-split #rx"[.]" the-version))]
|
||||
[concat
|
||||
(lambda xs
|
||||
(apply bytes-append
|
||||
(map (lambda (x) (if (string? x) (string->bytes/utf-8 x) x))
|
||||
xs)))]
|
||||
[commas "<1>, *<2>, *<3>, *<4>"]
|
||||
[periods "<1>.<2>.<3>.<4>"]
|
||||
[rc-patch (list (concat "\r\n *FILEVERSION "commas" *"
|
||||
"\r\n *PRODUCTVERSION "commas" *\r\n")
|
||||
(concat "\r\n *VALUE \"FileVersion\", *\""commas
|
||||
"(?:\\\\0)?\"")
|
||||
(concat "\r\n *VALUE \"ProductVersion\", *\""commas
|
||||
"(?:\\\\0)?\""))]
|
||||
[manifest-patch (list (concat "assemblyIdentity[ \r\n]+"
|
||||
"version=\""periods"\"[ \r\n]"))])
|
||||
`([#t ; only verify that it has the right contents
|
||||
"src/racket/src/schvers.h"
|
||||
,(concat "\n#define MZSCHEME_VERSION \"<1>.<2>"
|
||||
(if (parts# . >= . 3) ".<3>" "")
|
||||
(if (parts# . >= . 4) ".<4>" "")
|
||||
"\"\n")
|
||||
,@(for/list ([x+n (in-list '([X 1] [Y 2] [Z 3] [W 4]))])
|
||||
(format "\n#define MZSCHEME_VERSION_~a ~a\n"
|
||||
(car x+n)
|
||||
(if ((cadr x+n) . > . parts#)
|
||||
"0" (format "<~a>" (cadr x+n)))))]
|
||||
["src/worksp/racket/racket.rc" ,@rc-patch]
|
||||
["src/worksp/gracket/gracket.rc" ,@rc-patch]
|
||||
["src/worksp/starters/start.rc" ,@rc-patch]
|
||||
["src/worksp/racket/racket.manifest" ,@manifest-patch]
|
||||
["src/worksp/gracket/gracket.manifest" ,@manifest-patch]
|
||||
["src/worksp/mzcom/mzobj.rgs"
|
||||
,(concat "MzCOM.MzObj."periods" = s 'MzObj Class'")
|
||||
,(concat "CurVer = s 'MzCOM.MzObj."periods"'")
|
||||
,(concat "ProgID = s 'MzCOM.MzObj."periods"'")]
|
||||
["src/worksp/mzcom/mzcom.rc" ,@rc-patch
|
||||
#"\r\n *CTEXT +\"MzCOM v. <1>.<2>\",IDC_STATIC"
|
||||
#"\r\n *CTEXT +\"Racket v. <1>.<2>\",IDC_STATIC"])))
|
||||
|
||||
(define the-version #f)
|
||||
|
||||
(define getv
|
||||
(let ([vlist #f])
|
||||
(lambda (i)
|
||||
(unless vlist
|
||||
(set! vlist (map (compose string->bytes/utf-8 number->string)
|
||||
(version->list the-version))))
|
||||
(list-ref vlist i))))
|
||||
|
||||
(define (replace-pattern pattern buf err)
|
||||
(let* ([rx (regexp-replace* #rx#"<[1234]>" pattern #"([0-9]+)")]
|
||||
[vs (map (lambda (m)
|
||||
(let* ([m (regexp-replace #rx#"^<(.+)>$" m #"\\1")]
|
||||
[m (string->number (bytes->string/utf-8 m))])
|
||||
(sub1 m)))
|
||||
(regexp-match* #rx#"<[1234]>" pattern))]
|
||||
[m (regexp-match-positions rx buf)])
|
||||
(cond
|
||||
[(not m) (err "pattern ~s not found" pattern)]
|
||||
[(regexp-match? rx buf (cdar m))
|
||||
(err "pattern ~s matches more than once" pattern)]
|
||||
[else (let loop ([m (cdr m)] [i 0] [vs vs] [r '()])
|
||||
(cond [(and (null? m) (null? vs))
|
||||
(apply bytes-append (reverse (cons (subbytes buf i) r)))]
|
||||
[(or (null? m) (null? vs)) (error "internal error")]
|
||||
[else (loop (cdr m) (cdar m) (cdr vs)
|
||||
(list* (getv (car vs))
|
||||
(subbytes buf i (caar m))
|
||||
r))]))])))
|
||||
|
||||
(define (do-patch file . specs)
|
||||
(let* ([only-verify? (eq? file #t)]
|
||||
[file (if only-verify? (car specs) file)]
|
||||
[specs (if only-verify? (cdr specs) specs)]
|
||||
[_ (begin (printf " ~a..." file) (flush-output))]
|
||||
[contents (file->bytes file)]
|
||||
[buf contents]
|
||||
[err (lambda (fmt . args)
|
||||
(error 'versionpatch "~a, in ~s"
|
||||
(apply format fmt args) file))])
|
||||
(for ([spec (in-list specs)]) (set! buf (replace-pattern spec buf err)))
|
||||
(if (equal? buf contents)
|
||||
(printf (if only-verify? " verified.\n" " no change.\n"))
|
||||
(begin (printf " modified.\n")
|
||||
(if only-verify?
|
||||
(error 'versionpatch
|
||||
"this file is expected to have a correct version")
|
||||
(with-output-to-file file (lambda () (write-bytes buf))
|
||||
#:exists 'truncate))))))
|
||||
|
||||
(provide main)
|
||||
(define (main ver)
|
||||
(set! the-version ver)
|
||||
;; (printf "Patching files for ~a...\n" ver)
|
||||
(for ([p (in-list (patches))]) (apply do-patch p))
|
||||
(printf "Done.\n"))
|
|
@ -3,8 +3,7 @@
|
|||
(define name "Infrastructure code")
|
||||
(define compile-omit-paths '("images/taking-screenshots/racket-widget.scm"))
|
||||
(define test-omit-paths
|
||||
'("build"
|
||||
"check-dists.rkt"
|
||||
'("check-dists.rkt"
|
||||
"drdr"
|
||||
"drdr2"
|
||||
"images/mkheart.rkt"
|
||||
|
|
Loading…
Reference in New Issue
Block a user