Files
racket-wiki/private/vendor.rkt
T
2026-08-14 21:47:23 +02:00

107 lines
4.2 KiB
Racket

#lang racket/base
(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))