diff --git a/collects/version/check.rkt b/collects/version/check.rkt index aefa793578..f08d5756dd 100644 --- a/collects/version/check.rkt +++ b/collects/version/check.rkt @@ -1,4 +1,4 @@ -#lang scheme/base +#lang racket/base (define version-url "http://download.racket-lang.org/version.txt") (define timeout 30) @@ -13,9 +13,9 @@ (require scheme/tcp) (define (url->port url) - (define-values (host path) + (define-values [host path] (apply values (cdr (regexp-match #rx"^http://([^/:@]+)(/.*)$" url)))) - (define-values (i o) (tcp-connect host 80)) + (define-values [i o] (tcp-connect host 80)) (fprintf o "GET ~a HTTP/1.0\r\nHost: ~a\r\n\r\n" path host) (flush-output o) (close-output-port o) @@ -27,29 +27,26 @@ (case-lambda [(what) `(error ,what)] [(what more) - `(error ,what - ,(cond [(list? more) (format "~a" more)] - [(exn? more) (format "(~a)" (exn-message more))] - [else (format "(~a)" more)]))])) + `(error ,what ,(cond [(list? more) (format "~a" more)] + [(exn? more) (format "(~a)" (exn-message more))] + [else (format "(~a)" more)]))])) (define (with-timeout timeout thunk) (define result #f) - (let ([r (sync/timeout timeout - (thread (lambda () - (set! result - (with-handlers - ([void (lambda (e) - (error-value "internal error" e))]) - (thunk))))))]) - (if r result (error-value "timeout")))) + (define r (sync/timeout timeout + (thread (λ () + (set! result + (with-handlers + ([void (λ (e) + (error-value "internal error" e))]) + (thunk))))))) + (if r result (error-value "timeout"))) (define (check-version-raw) (let/ec escape (define (err . args) (escape (apply error-value args))) - (define-syntax try - (syntax-rules () - [(_ expr error-message) - (with-handlers ([void (lambda (e) (err error-message e))]) expr)])) + (define-syntax-rule (try expr error-message) + (with-handlers ([void (λ (e) (err error-message e))]) expr)) ;; Get server information, carefully (define version-info (parameterize ([current-input-port @@ -60,38 +57,35 @@ (cond [(assq key version-info) => cadr] [else (err (format "no `~s' in response" key) version-info)])) (define (getver key) - (let ([ver (get key)]) - (if (valid-version? ver) - ver - (err "bad version string from server" key)))) + (define ver (get key)) + (if (valid-version? ver) ver (err "bad version string from server" key))) (unless (and (list? version-info) - (andmap (lambda (x) - (and (list? x) - (= 2 (length x)) - (symbol? (car x)) - (string? (cadr x)))) + (andmap (λ (x) (and (list? x) + (= 2 (length x)) + (symbol? (car x)) + (string? (cadr x)))) version-info)) (err "bad response from server" version-info)) ;; Make a decision - (let ([current (version)] - [stable (getver 'stable)] - [recent (getver 'recent)]) - (cond - ;; we have the newest version (can be > if we have a build from git) - [(version<=? recent current) 'ok] - ;; we're stable, but there's a newer version - [(version<=? stable current) `(ok-but ,recent)] - ;; new version out -- no alphas or we have an alpha => show recent - [(or (equal? recent stable) - (and (alpha-version? current) - ;; but if we have an alpha that is older then the current - ;; stable then go to the next case - (version<=? stable current))) - `(newer ,recent)] - ;; new version out, we have an outdated stable, there is also an alpha - ;; (alternatively, we have an alpha that is older than the current - ;; stable) - [else `(newer ,stable ,recent)])))) + (define current (version)) + (define stable (getver 'stable)) + (define recent (getver 'recent)) + (cond + ;; we have the newest version (can be > if we have a build from git) + [(version<=? recent current) 'ok] + ;; we're stable, but there's a newer version + [(version<=? stable current) `(ok-but ,recent)] + ;; new version out -- no alphas or we have an alpha => show recent + [(or (equal? recent stable) + (and (alpha-version? current) + ;; but if we have an alpha that is older then the current + ;; stable then go to the next case + (version<=? stable current))) + `(newer ,recent)] + ;; new version out, we have an outdated stable, there is also an alpha + ;; (alternatively, we have an alpha that is older than the current + ;; stable) + [else `(newer ,stable ,recent)]))) ;; Check the version on the server and compare to our version. Possible return ;; values (message is always a string): diff --git a/collects/version/doc.txt b/collects/version/doc.txt deleted file mode 100644 index 701347d8bc..0000000000 --- a/collects/version/doc.txt +++ /dev/null @@ -1,47 +0,0 @@ -_version_: Racket version checking -================================== - -The version collection contains several version-related pieces that -are used by Racket. First, the "check.ss" module provides a single -function: - -> (check-version) - -This procedure checks the currently available version on the Racket -website (doanload.racket-lang.org), and returns a value that indicates -your current state -- one of these: - - * `ok - You're fine. - * `(ok-but ,version) - You have a fine stable version, but note that there is a newer - alpha version available - * `(newer ,version) - You have an old version, please upgrade to `version' - * `(newer ,version ,alpha) - You have an old-but-stable version, please upgrade to `version'; - you may consider also the newer alpha version - * `(error ,message [,additional-info]) - An error occurred, the message is a string that indicates the - error. - The third (optional) value is a string that can be shown as the - system error that happened. This string will always be - parenthesized, so `message' is a short error and - `(string-append message " " additional-info)' is a verbose one. - -The second functionality that is provided by this collection is in the -_patchlevel_ module. This module provides a single value: - -> patchlevel - -which is an integer that indicates the current patch level. This is -normally zero, but may be updated by patches to DrRacket. - - -Finally, the "tool.rkt" makes DrRacket use both features: - -* the patchlevel appears as a version `pN' suffix in DrRacket (but the - binary version as reported by `(version)' is not changed); - -* it is possible to periodically check whether a new Racket - distribution is available for download. diff --git a/collects/version/patchlevel.rkt b/collects/version/patchlevel.rkt index 041db37679..044e41c00f 100644 --- a/collects/version/patchlevel.rkt +++ b/collects/version/patchlevel.rkt @@ -1,5 +1,5 @@ ;; This file contains the current patch level of Racket. ;; It is usually `0' in the repository, changes only when a patch is made. -#lang scheme/base +#lang racket/base (define patchlevel 0) (provide patchlevel) diff --git a/collects/version/tool.rkt b/collects/version/tool.rkt index 8466c52ab3..a3731bbbd2 100644 --- a/collects/version/tool.rkt +++ b/collects/version/tool.rkt @@ -1,6 +1,6 @@ -#lang scheme/gui +#lang racket/gui -(require scheme/unit scheme/class framework drscheme/tool +(require racket/unit racket/class framework drracket/tool browser/external string-constants "patchlevel.rkt" "check.rkt") @@ -29,10 +29,10 @@ (define top (and (pair? top?) (car top?))) ;; wait until the definitions are instantiated, return top-level window (define (wait-for-definitions) - (let ([ws (get-top-level-windows)]) - (if (null? ws) - (begin (sleep 1) (wait-for-definitions)) - (car ws)))) + (define ws (get-top-level-windows)) + (if (null? ws) + (begin (sleep 1) (wait-for-definitions)) + (car ws))) #| ;; Cute code, but may resize the window if too much space, and people ;; didn't like this way of asking if you want update checks. ;; show a message and a disable button @@ -40,112 +40,108 @@ (define (show-message first-time?) ;; No info display if we got some non-drscheme window by accident (cond - [(with-handlers ([void (lambda _ #f)]) (send top get-info-panel)) => - (lambda (info) - (sleep 3) ; wait to make this appearance visible - (let* ([-check "Checking for updates..."] - [-about "About to auto-check for updates, you can"] - [p (make-object horizontal-panel% info)] - [m (make-object message% (if first-time? -about -check) p)] - [b (make-object button% "Disable" p disable)]) - (send info change-children (lambda (l) (cons p (remq p l)))) - (when first-time? - (let ([m1 (make-object message% "these checks" p)]) - (sleep 20) - (send p change-children (lambda (l) (remq m1 l)))) - (send m set-label -check)) - (sleep 2) ; wait before and after check to make it visible - (set! hide-message - (lambda now? - (unless (and (pair? now?) (car now?)) (sleep 1)) - (send info change-children (lambda (l) (remq p l))) - (set! hide-message void)))) - #t)] ; return #t so that the check starts + [(with-handlers ([void (λ _ #f)]) (send top get-info-panel)) => + (λ (info) + (sleep 3) ; wait to make this appearance visible + (define -check "Checking for updates...") + (define -about "About to auto-check for updates, you can") + (define p (make-object horizontal-panel% info)) + (define m (make-object message% (if first-time? -about -check) p)) + (define b (make-object button% "Disable" p disable)) + (send info change-children (λ (l) (cons p (remq p l)))) + (when first-time? + (define m1 (make-object message% "these checks" p)) + (sleep 20) + (send p change-children (λ (l) (remq m1 l))) + (send m set-label -check)) + (sleep 2) ; wait before and after check to make it visible + (set! hide-message + (λ ([now? #f]) + (unless now? (sleep 1)) + (send info change-children (λ (l) (remq p l))) + (set! hide-message void))) + #t)] ; return #t so that the check starts [else #f])) ; no standard window -- return #f to skip the whole thing |# ;; show results in a dialog in a non-modal dialog (if it was not an ;; explicit call) , so the window can be left around as a reminder. (define (message style fmt . args) (define (run) - (let-values ([(result new-enabled?) - (message+check-box/custom - (string-constant version:results-title) - (apply format fmt args) - (string-constant version:do-periodic-checks) - (string-constant ok) - (and (eq? 'newer style) - (string-constant version:take-me-there)) - #f - (and explicit? top) - `(,@(case style - [(#f) '()] [(newer) '(stop)] [else (list style)]) - ,@(if enabled? '(checked) '()) - default=1))]) - (unless (eq? enabled? new-enabled?) - (preferences:set 'updates:enabled? (if new-enabled? 'yes 'no)) - (set! enabled? new-enabled?)) - result)) + (define-values [result new-enabled?] + (message+check-box/custom + (string-constant version:results-title) + (apply format fmt args) + (string-constant version:do-periodic-checks) + (string-constant ok) + (and (eq? 'newer style) (string-constant version:take-me-there)) + #f + (and explicit? top) + `(,@(case style + [(#f) '()] [(newer) '(stop)] [else (list style)]) + ,@(if enabled? '(checked) '()) + default=1))) + (unless (eq? enabled? new-enabled?) + (preferences:set 'updates:enabled? (if new-enabled? 'yes 'no)) + (set! enabled? new-enabled?)) + result) (if explicit? (run) ;; non-modal (parameterize ([current-eventspace (make-eventspace)]) (run)))) ;; main checker (define (check) - (let ([result #f]) - ;; run the check in a thread, with a chance to abort it - (let* ([d #f] - [t (thread (lambda () - (set! result (check-version)) - (when d (send d show #f))))]) - (unless (sync/timeout .4 t) ; still checking, pop message - (when explicit? ; unless it's an automatic check - (queue-callback - (lambda () - (set! d (new (class dialog% - (super-new - [label (string-constant version:update-check)] - [parent #f]) - (make-object message% - (string-constant version:connecting-server) - this) - (make-object button% - (string-constant abort) this - (lambda (b e) - (kill-thread t) - (send this show #f)) - '(border)) - (send this center)))) - (send d show #t))) - (sleep/yield .5)) - (thread-wait t))) - (cond - [(and (pair? result) (eq? 'newer (car result))) - (when (equal? 2 (message 'newer "Racket v~a ~a ~a" - (cadr result) - (string-constant version:now-available-at) - download-url)) - ;; 2 = go there - (send-url download-url) - ;; (sleep 1) ((application-quit-handler)) - )] - ;; implicit auto-check => show a message only if there is a newer - ;; version => the rest are only for explicit calls - [(not explicit?) (void)] - [(eq? result 'ok) - (message #f (string-constant version:plt-up-to-date))] - [(not (pair? result)) (void)] ; either #f (canceled) or ok - [else (case (car result) - [(error) - (message 'stop "~a: ~a~a" - (string-constant error) (cadr result) - (if (pair? (cddr result)) - (string-append "\n" (caddr result)) ""))] - [(ok-but) - (message 'caution "~a,\n~a (v~a)" - (string-constant version:plt-up-to-date) - (string-constant version:but-newer-alpha) - (cadr result))] - [else (error 'check-for-updates "internal error")])]))) + (define result #f) + ;; run the check in a thread, with a chance to abort it + (let ([d #f]) + (define t (thread (λ () (set! result (check-version)) + (when d (send d show #f))))) + (unless (sync/timeout .4 t) ; still checking, pop message + (when explicit? ; unless it's an automatic check + (queue-callback + (λ () + (set! d (new (class dialog% + (super-new + [label (string-constant version:update-check)] + [parent #f]) + (make-object message% + (string-constant version:connecting-server) + this) + (make-object button% + (string-constant abort) this + (λ (b e) (kill-thread t) (send this show #f)) + '(border)) + (send this center)))) + (send d show #t))) + (sleep/yield .5)) + (thread-wait t))) + (cond + [(and (pair? result) (eq? 'newer (car result))) + (when (equal? 2 (message 'newer "Racket v~a ~a ~a" + (cadr result) + (string-constant version:now-available-at) + download-url)) + ;; 2 = go there + (send-url download-url) + ;; (sleep 1) ((application-quit-handler)) + )] + ;; implicit auto-check => show a message only if there is a newer + ;; version => the rest are only for explicit calls + [(not explicit?) (void)] + [(eq? result 'ok) + (message #f (string-constant version:plt-up-to-date))] + [(not (pair? result)) (void)] ; either #f (canceled) or ok + [else (case (car result) + [(error) + (message 'stop "~a: ~a~a" + (string-constant error) (cadr result) + (if (pair? (cddr result)) + (string-append "\n" (caddr result)) ""))] + [(ok-but) + (message 'caution "~a,\n~a (v~a)" + (string-constant version:plt-up-to-date) + (string-constant version:but-newer-alpha) + (cadr result))] + [else (error 'check-for-updates "internal error")])])) ;; start the check if enabled and enough time passed (when (or explicit? enabled?) (unless top (set! top (wait-for-definitions))) @@ -163,25 +159,25 @@ (define (phase1) (void)) (define (phase2) (preferences:add-to-warnings-checkbox-panel - (lambda (panel) - (let ([b (make-object check-box% - (string-constant version:do-periodic-checks) - panel - (lambda (b e) - (preferences:set 'updates:enabled? - (if (send b get-value) 'yes 'no))))]) - (preferences:add-callback - 'updates:enabled? - (lambda (p v) (send b set-value (is-enabled? v)))) - (send b set-value - (is-enabled? (preferences:get 'updates:enabled?)))))) + (λ (panel) + (define b + (make-object check-box% + (string-constant version:do-periodic-checks) + panel + (λ (b e) (preferences:set 'updates:enabled? + (if (send b get-value) 'yes 'no))))) + (preferences:add-callback + 'updates:enabled? + (λ (p v) (send b set-value (is-enabled? v)))) + (send b set-value + (is-enabled? (preferences:get 'updates:enabled?))))) (drscheme:get/extend:extend-unit-frame - (lambda (f%) + (λ (f%) (class f% (define/override (help-menu:after-about m) (make-object menu-item% (string-constant version:update-menu-item) m - (lambda (b e) (check-for-updates this))) + (λ (b e) (check-for-updates this))) (super help-menu:after-about m)) (super-new)))) (thread check-for-updates)) diff --git a/collects/version/utils.rkt b/collects/version/utils.rkt index 5decb550b6..58a77e51e8 100644 --- a/collects/version/utils.rkt +++ b/collects/version/utils.rkt @@ -1,4 +1,4 @@ -#lang scheme/base +#lang racket/base (provide valid-version? version->list versioninteger) @@ -17,16 +17,15 @@ ;; returns a list of 4 integers (see src/mzscheme/src/schvers.h) (define (version->list str) - (let ([ver (map string->number (regexp-split #rx"[.]" str))]) - (case (length ver) - [(2) (append ver '(0 0))] - [(3) (append ver '(0))] - [(4) ver] - [else (error 'version->list "bad version: ~e" str)]))) + (define ver (map string->number (regexp-split #rx"[.]" str))) + (case (length ver) + [(2) (append ver '(0 0))] + [(3) (append ver '(0))] + [(4) ver] + [else (error 'version->list "bad version: ~e" str)])) (define (versionlist a)] - [b (version->list b)]) + (let loop ([a (version->list a)] [b (version->list b)]) (cond [(null? a) #f] [(< (car a) (car b)) #t] [(> (car a) (car b)) #f] @@ -36,10 +35,10 @@ (or (equal? a b) (versionlist v)]) - (or ((list-ref l 1) . >= . 90) - ((list-ref l 2) . >= . 900) - ((list-ref l 3) . >= . 900)))) + (define l (version->list v)) + (or ((list-ref l 1) . >= . 90) + ((list-ref l 2) . >= . 900) + ((list-ref l 3) . >= . 900))) ;; returns an integer representing the version (XXYYZZZWWW) or #f if invalid ;; works for pre v4 versions too @@ -54,20 +53,19 @@ [(< n 49) ver] ;; old versions (earliest useful is 49, changed at 3.99) [(<= 49 n 379) - (let*-values - ([(q r) (quotient/remainder n 100)] - [(sfx) (substring ver (cdar m))] - [(sfx) (cond [(equal? sfx "") ""] - ;; NNNpN -> N.NN.N - [(regexp-match? #rx"^p[0-9]" sfx) - (string-append "." (substring sfx 1))] - ;; NNN.N -> N.NN.0.N (not a release version) - [(regexp-match? #rx"^[.]" sfx) - (string-append ".0" sfx)] - [else #f])]) - (and sfx (format "~a.~a~a" q r sfx)))] + (define-values [q r] (quotient/remainder n 100)) + (define sfx (let ([sfx (substring ver (cdar m))]) + (cond [(equal? sfx "") ""] + ;; NNNpN -> N.NN.N + [(regexp-match? #rx"^p[0-9]" sfx) + (string-append "." (substring sfx 1))] + ;; NNN.N -> N.NN.0.N (not a release version) + [(regexp-match? #rx"^[.]" sfx) + (string-append ".0" sfx)] + [else #f]))) + (and sfx (format "~a.~a~a" q r sfx))] ;; bad strings [else #f])) (and v (valid-version? v) - (foldl (lambda (ver mul acc) (+ ver (* mul acc))) 0 + (foldl (λ (ver mul acc) (+ ver (* mul acc))) 0 (version->list v) '(0 100 1000 1000)))) diff --git a/collects/version/version.scrbl b/collects/version/version.scrbl index becaad8d87..eb40425218 100644 --- a/collects/version/version.scrbl +++ b/collects/version/version.scrbl @@ -12,8 +12,8 @@ @title{Version: Racket Version Checking} -The version collection contains several version-related pieces that -are used by Racket. See also @racket[version] from +The @racketmodname[version] collection contains several version-related +pieces that are used by Racket. See also @racket[version] from @racketmodname[racket/base]. @; ---------------------------------------------------------------------- @@ -39,36 +39,34 @@ Checks the currently available version on the PLT website (@selflink["http://download.racket-lang.org"]) and returns a value that indicates the current state of the curent installation: - @itemize[ +@itemize[ - @item{@racket[`ok] --- You're fine.} +@item{@racket[`ok] --- You're fine.} - @item{@racket[`(ok-but ,_version)] --- You have a fine stable - version, but note that there is a newer alpha version available - numbered @racket[_version].} +@item{@racket[`(ok-but ,_version)] --- You have a fine stable + version, but note that there is a newer alpha version available + numbered @racket[_version].} - @item{@racket[`(newer ,_version)] --- You have an old - version. Please upgrade to @racket[_version].} +@item{@racket[`(newer ,_version)] --- You have an old + version. Please upgrade to @racket[_version].} - @item{@racket[`(newer ,_version ,_alpha)] --- You have an - old-but-stable version, please upgrade to @racket[_version]; you - may consider also the newer alpha version numbered - @racket[_alpha].} +@item{@racket[`(newer ,_version ,_alpha)] --- You have an + old-but-stable version, please upgrade to @racket[_version]; you + may consider also the newer alpha version numbered + @racket[_alpha].} - @item{@racket[`(error ,_message)] --- An error occurred, and - @racket[_message] is a string that indicates the error.} +@item{@racket[`(error ,_message)] --- An error occurred, and + @racket[_message] is a string that indicates the error.} - @item{@racket[`(error ,_message ,_additional-info)] --- An error - occurred; @racket[_message] is a string that indicates the - error, and @racket[_additional-info] is a string containing a - system error. The @racket[_additional-info] content is always - parenthesizes, so @racket[message] is a short error and - @racket[(string-append message " " additional-info)] is a - verbose one.} +@item{@racket[`(error ,_message ,_additional-info)] --- An error + occurred; @racket[_message] is a string that indicates the + error, and @racket[_additional-info] is a string containing a + system error. The @racket[_additional-info] content is always + parenthesizes, so @racket[message] is a short error and + @racket[(string-append message " " additional-info)] is a + verbose one.} - ] - -} +]} @; ---------------------------------------------------------------------- @@ -80,11 +78,11 @@ The @racket[version/tool] library implements a DrRacket tool that @itemize[ - @item{makes the patchlevel display as a version @tt{p}@nonterm{N} +@item{makes the patchlevel display as a version @tt{p}@nonterm{N} suffix in DrRacket (though the base verion reported by @racket[(version)] is not changed);} - @item{if enabled by the user, periodically checks whether a +@item{if enabled by the user, periodically checks whether a new Racket distribution is available for download.} ] @@ -94,48 +92,41 @@ The @racket[version/tool] library implements a DrRacket tool that @section{Version Utilities} @defmodule[version/utils]{ - -The @racketmodname[version/utils] library provides a few of convenient -utilities for dealing with version strings. Unless explicitly noted, -these functions do not handle legacy versions of Racket.} + The @racketmodname[version/utils] library provides a few of convenient + utilities for dealing with version strings. Unless explicitly noted, + these functions do not handle legacy versions of Racket.} @defproc[(valid-version? [str string?]) boolean?]{ - -Returns @racket[#t] if @racket[str] is a valid Racket version -string, @racket[#f] otherwise.} + Returns @racket[#t] if @racket[str] is a valid Racket version + string, @racket[#f] otherwise.} @defproc[(version->list [str valid-version?]) (list integer? integer? integer? integer?)]{ - -Returns a list of four numbers that the given version string -represent. @racket[str] is assumed to be a valid version.} + Returns a list of four numbers that the given version string + represent. @racket[str] is assumed to be a valid version.} @defproc[(versioninteger [str string?]) (or/c integer? false/c)]{ + Converts the version string into an integer. For version + @racket["X.YY.ZZZ.WWW"], the result will be @racketvalfont{XYYZZZWWW}. + This function works also for legacy Racket versions, by + translating @racket["XYY.ZZZ"] to @racketvalfont{XYYZZZ000}. The + resulting integer can thefore be used to conveniently compare any two + (valid) version strings. If the version string is invalid the + resulting value is @racket[#f]. -Converts the version string into an integer. For version -@racket["X.YY.ZZZ.WWW"], the result will be @racketvalfont{XYYZZZWWW}. -This function works also for legacy Racket versions, by -translating @racket["XYY.ZZZ"] to @racketvalfont{XYYZZZ000}. The -resulting integer can thefore be used to conveniently compare any two -(valid) version strings. If the version string is invalid the -resulting value is @racket[#f]. - -Note that this is the only function that deals with legacy version -strings.} + Note that this is the only function that deals with legacy version + strings.}