111 lines
4.4 KiB
Racket
111 lines
4.4 KiB
Racket
#lang racket/base
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Pinned frontend dependency download and verification.
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(require net/url
|
|
net/url-connect
|
|
racket/file
|
|
racket/path
|
|
racket/port
|
|
"config.rkt")
|
|
|
|
(provide vendor-files
|
|
vendor-files-ready?
|
|
download-vendor-files!)
|
|
|
|
(define vendor-files
|
|
(list
|
|
(cons "font-awesome/css/font-awesome.min.css"
|
|
"https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css")
|
|
(cons "font-awesome/fonts/fontawesome-webfont.woff2"
|
|
"https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/fonts/fontawesome-webfont.woff2")
|
|
(cons "easymde.min.js"
|
|
"https://cdn.jsdelivr.net/npm/easymde@2.21.0/dist/easymde.min.js")
|
|
(cons "easymde.min.css"
|
|
"https://cdn.jsdelivr.net/npm/easymde@2.21.0/dist/easymde.min.css")
|
|
(cons "purify.min.js"
|
|
"https://cdn.jsdelivr.net/npm/dompurify@3.4.13/dist/purify.min.js")
|
|
(cons "highlight.min.js"
|
|
"https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.12.0/build/highlight.min.js")
|
|
(cons "highlight-scheme.min.js"
|
|
"https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.12.0/build/languages/scheme.min.js")
|
|
(cons "highlight-github.min.css"
|
|
"https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.12.0/build/styles/github.min.css")
|
|
(cons "diff2html-ui-base.min.js"
|
|
"https://cdn.jsdelivr.net/npm/diff2html@3.4.56/bundles/js/diff2html-ui-base.min.js")
|
|
(cons "diff2html.min.css"
|
|
"https://cdn.jsdelivr.net/npm/diff2html@3.4.56/bundles/css/diff2html.min.css")))
|
|
|
|
(define (vendor-file-ready? config name)
|
|
(define path (build-path (vendor-directory config) name))
|
|
(and (file-exists? path)
|
|
(> (file-size path) 0)))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
; goal : Check whether all required browser libraries are installed.
|
|
; pre : config is a wiki-config value.
|
|
; post : Vendor files have only been inspected.
|
|
; result : #t when every required vendor file exists and is non-empty,
|
|
; otherwise #f.
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
(define (vendor-files-ready? config)
|
|
(for/and ([entry (in-list vendor-files)])
|
|
(vendor-file-ready? config (car entry))))
|
|
|
|
(define (download-content source)
|
|
(parameterize ((current-https-protocol 'secure))
|
|
(define-values (in headers)
|
|
(get-pure-port/headers (string->url source)
|
|
'()
|
|
#:redirections 5
|
|
#:status? #t))
|
|
(dynamic-wind
|
|
void
|
|
(λ ()
|
|
(define status-match
|
|
(regexp-match #px"^HTTP/[^ ]+ ([0-9][0-9][0-9])" headers))
|
|
(unless (and status-match
|
|
(= (string->number (list-ref status-match 1)) 200))
|
|
(error 'download-vendor-files!
|
|
"download failed for ~a: ~a"
|
|
source
|
|
(or (and status-match (list-ref status-match 1))
|
|
"invalid HTTP status")))
|
|
(port->bytes in))
|
|
(λ ()
|
|
(close-input-port in)))))
|
|
|
|
(define (download-file! config name source)
|
|
(define directory (vendor-directory config))
|
|
(define target (build-path directory name))
|
|
(define temporary-target
|
|
(build-path directory (string-append name ".download")))
|
|
(define content (download-content source))
|
|
(make-directory* (path-only target))
|
|
(call-with-output-file temporary-target
|
|
(λ (out)
|
|
(write-bytes content out))
|
|
#:exists 'truncate/replace)
|
|
(rename-file-or-directory temporary-target target #t)
|
|
(void))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
; goal : Download all browser libraries required by the wiki frontend.
|
|
; pre : config identifies a writable data directory and outbound HTTPS is
|
|
; available for the configured vendor URLs.
|
|
; post : Every required vendor file is stored below data/static/vendor.
|
|
; result : void.
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
(define (download-vendor-files! config)
|
|
(make-directory* (vendor-directory config))
|
|
(for ([entry (in-list vendor-files)])
|
|
(define name (car entry))
|
|
(define source (cdr entry))
|
|
(unless (vendor-file-ready? config name)
|
|
(download-file! config name source)))
|
|
(unless (vendor-files-ready? config)
|
|
(error 'download-vendor-files! "frontend vendor setup is incomplete"))
|
|
(void))
|