Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -13,6 +13,6 @@ *.ltx *.aux *.log *.xml *.toc - +*.mark Index: blog.rkt ================================================================== --- blog.rkt +++ blog.rkt @@ -26,33 +26,35 @@ (require "crystalize.rkt" "snippets-html.rkt" racket/file sugar/list) + +(provide main) ;; How many items per blog page -(define per-page 1) +(define per-page 5) ;; Returns a string containing the entire HTML contents of a given blog page (define (blog-page posts-str pagenum total-pages) (define page-nav (html$-paginate-navlinks pagenum total-pages "blog")) ◊string-append{ - - -◊html$-page-head[(format "The Local Yarn: Blog, p. ~a" pagenum)] -◊html$-page-body-open[] - - - - - -◊posts-str - - - -◊html$-page-body-close[] -}) + + + ◊html$-page-head[(format "The Local Yarn: Blog, p. ~a" pagenum)] + ◊html$-page-body-open[] + + + + + + ◊posts-str + + + + ◊html$-page-body-close[] + }) ;; Grabs all the articles+notes from the cache and writes out all the blog page files (define (build-blog) (spell-of-summoning!) ; Turn on the DB @@ -60,13 +62,14 @@ (define pagecount (length articles+notes)) (for ([pagenum (in-range 1 (+ 1 pagecount))] [page (in-list articles+notes)]) (define filename (format "blog-pg~a.html" pagenum)) - (println (format "Writing: ~a" filename)) + (displayln (format "Writing: ~a" filename)) (display-to-file (blog-page (apply string-append page) pagenum pagecount) filename #:mode 'text #:exists 'replace))) -;; Do it! -(build-blog) +(define (main) + ;; Do it! + (build-blog)) Index: dust.rkt ================================================================== --- dust.rkt +++ dust.rkt @@ -27,10 +27,11 @@ pollen/file net/uri-codec gregor txexpr racket/list + racket/system racket/string) ;; Provides common helper functions used throughout the project (provide maybe-meta ; Select from (current-metas) or default value ("") if not available @@ -37,10 +38,11 @@ maybe-attr ; Return an attribute’s value or a default ("") if not available here-output-path series-noun ; Retrieve noun-singular from current 'series meta, or "" series-title ; Retrieve title of series in current 'series meta, or "" series-pagenode + invalidate-series make-tag-predicate tx-strs ymd->english ymd->dateformat default-authorname @@ -59,13 +61,15 @@ (define series-folder "series") (define articles-folder "articles") (define (default-title body-txprs) (format "“~a…”" (first-words body-txprs 5))) + (define (maybe-meta m [missing ""]) - (or (select-from-metas m (current-metas)) missing)) + (cond [(current-metas) (or (select-from-metas m (current-metas)) missing)] + [else missing])) ;; Return the current output path, relative to (current-project-root) ;; Similar to the variable 'here' which is only accessible in Pollen templates, ;; except this is an actual path, not a string. (define (here-output-path) @@ -94,10 +98,23 @@ (define (series-title) (define series-pnode (series-pagenode)) (case series-pnode ['|| ""] ; no series specified [else (or (select-from-metas 'title series-pnode) "")])) + +;; “Touches” the last-modified date on the current article’s series, if there is one + +(define (invalidate-series) + (define series-name (maybe-meta 'series #f)) + (when series-name + (define series-file (build-path (current-project-root) + series-folder + (format "~a.poly.pm" series-name))) + (when (file-exists? series-file) + (case (system-type 'os) + ['windows (system (format "type nul >> ~a" series-file))] + [else (system (format "touch ~a" series-file))])))) ;; ~~~ Project-wide Pagetrees ~~~ (define (include-in-pagetree folder extension) (define (matching-file? f) Index: makefile ================================================================== --- makefile +++ makefile @@ -4,16 +4,85 @@ # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. This file is offered as-is, # without any warranty. # +SHELL = /bin/bash + +# ~~~ Variables used by rules ~~~ +# + +core-files := pollen.rkt dust.rkt +html-deps := snippets-html.rkt tags-html.rkt + +article-sources := $(wildcard articles/*.poly.pm) +articles-html := $(patsubst %.poly.pm, %.html, $(article-sources)) +articles-pdf := $(patsubst %.poly.pm, %.pdf, $(article-sources)) + +series-sources := $(wildcard series/*.poly.pm) +series-html := $(patsubst %.poly.pm, %.html, $(series-sources)) + +# ~~~ Rules ~~ +# + +# The order of these dependencies is important. They will be processed left to right. +web: _article_htmls.mark $(articles-html) $(series-html) blog-pg1.html +web: ## Rebuild all web content (not PDFs) + +# The file article_htmls.mark is a zero-byte file that serves only as a marker. If it is older than +# any of its dependencies (or missing) all of the articles will be rebuilt. Its dependencies are +# also on the Pollen cache watchlist (see pollen.rkt) +_article_htmls.mark: $(core-files) $(html-deps) template.html.p + raco pollen setup articles/ + raco pollen render -p -t html articles/*.poly.p + raco pollen setup series/ + raco pollen render -p -t html series/*.poly.pm + touch article_htmls.mark + +# If the rule for article_htmls.mark was triggered, all the article HTML files will already have +# been re-rendered. (That rule comes before this one in the list of dependencies for "all") But if +# not, any individual files that have been edited will get re-rendered. +$(articles-html): %.html: %.poly.pm + raco pollen render $@ + +# Note that if any article is part of a series, it will touch its series .poly.pm file during its +# render, triggering this rule for that series. +$(series-html): %.html: %.poly.pm + raco pollen render $@ +# This target will also rebuild pg2, pg3, etc. +blog-pg1.html: $(core-files) $(html-deps) $(articles-html) blog.rkt + rm -f blog*.html + racket -tm blog.rkt spritz: ## Clear Pollen and Scribble cache rm -rf compiled code-docs/compiled articles/compiled series/compiled fossil clean code-docs/ +publish: check-env +publish: ## Sync all HTML and PDF stuff to the public web server (does not rebuild any files) + raco pollen publish + rsync -av ~/Desktop/publish/ -e 'ssh -p $(WEB_SRV_PORT)' $(LOCALYARN_SRV) \ + --delete \ + --exclude=drafts \ + --exclude=code-docs \ + --exclude=util \ + --exclude=x-mockup \ + --exclude=repo-www \ + --exclude=scribbled \ + --exclude='*.sqlite' \ + --exclude='*.fossil' \ + --exclude=.fossil-settings \ + --exclude=.fslckout \ + --exclude='*.ltx' \ + --exclude='*.swp' \ + --exclude='*.mark' \ + --exclude=.DS_Store \ + --exclude='template*.*' \ + --exclude=makefile + rm -rf ~/Desktop/publish + scribble: ## Rebuild code documentation and update Fossil repo scribble --htmls +m --redirect https://docs.racket-lang.org/local-redirect/ code-docs/main.scrbl fossil uv rm scribbled/* rm -rf scribbled/* mv main/* scribbled/ @@ -27,8 +96,16 @@ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' article: ## Start a new article from a template racket util/newpost.rkt -.PHONY: scribble help spritz article +.PHONY: all scribble help spritz article publish check-env .DEFAULT_GOAL := help + +check-env: +ifndef LOCALYARN_SRV + $(error LOCALYARN_SRV env variable not set, should be a destination valid for rsync) +endif +ifndef WEB_SRV_PORT + $(error WEB_SRV_PORT env variable not set, should be SSH port number for web server) +endif Index: tags-html.rkt ================================================================== --- tags-html.rkt +++ tags-html.rkt @@ -95,10 +95,11 @@ (define (html-block . elements) `(section [[class "content-block"]] (div [[class "content-block-main"]] ,@elements))) (define (html-root . elements) + (invalidate-series) (define first-pass (decode-elements (append elements (list (html-footnote-block))) #:txexpr-elements-proc decode-hardwrapped-paragraphs #:exclude-tags '(script style figure table pre))) (define second-pass