Add the `site-posts-output-directory` field.

- Remove the "prefix" argument from the theme objects in the blog
  builder.
- Remove the "blog-prefix" argument from the rss and atom builders.

A user can specify the output directory for the posts in the SITE
record, this, together with the SITE-SLUG function, allows one to
generate relative and absolute URLs to the posts. This information is
used in all the builders that operate on posts collections.
This commit is contained in:
Dan Frumin 2019-06-29 14:29:28 +02:00
parent 65adbb052f
commit 0130760f3f
5 changed files with 56 additions and 50 deletions

View File

@ -136,14 +136,9 @@
"Convert date to RFC-3339 formatted string." "Convert date to RFC-3339 formatted string."
(date->string date "~Y-~m-~dT~H:~M:~SZ")) (date->string date "~Y-~m-~dT~H:~M:~SZ"))
(define* (post->atom-entry site post #:key (blog-prefix "")) (define* (post->atom-entry site post)
"Convert POST into an Atom <entry> XML node." "Convert POST into an Atom <entry> XML node."
(let ((uri (uri->string (let ((uri (uri->string (site-post-url site post))))
(build-uri (site-scheme site)
#:host (site-domain site)
#:path (string-append blog-prefix "/"
(site-post-slug site post)
".html")))))
`(entry `(entry
(title ,(post-ref post 'title)) (title ,(post-ref post 'title))
(id ,uri) (id ,uri)
@ -170,8 +165,7 @@
(file-name "feed.xml") (file-name "feed.xml")
(subtitle "Recent Posts") (subtitle "Recent Posts")
(filter posts/reverse-chronological) (filter posts/reverse-chronological)
(max-entries 20) (max-entries 20))
(blog-prefix ""))
"Return a builder procedure that renders a list of posts as an Atom "Return a builder procedure that renders a list of posts as an Atom
feed. All arguments are optional: feed. All arguments are optional:
@ -194,16 +188,14 @@ MAX-ENTRIES: The maximum number of posts to render in the feed"
"/" file-name)) "/" file-name))
(rel "self"))) (rel "self")))
(link (@ (href ,(site-domain site)))) (link (@ (href ,(site-domain site))))
,@(map (cut post->atom-entry site <> ,@(map (cut post->atom-entry site <>)
#:blog-prefix blog-prefix)
(take-up-to max-entries (filter posts)))) (take-up-to max-entries (filter posts))))
sxml->xml*)))) sxml->xml*))))
(define* (atom-feeds-by-tag #:key (define* (atom-feeds-by-tag #:key
(prefix "feeds/tags") (prefix "feeds/tags")
(filter posts/reverse-chronological) (filter posts/reverse-chronological)
(max-entries 20) (max-entries 20))
(blog-prefix ""))
"Return a builder procedure that renders an atom feed for every tag "Return a builder procedure that renders an atom feed for every tag
used in a post. All arguments are optional: used in a post. All arguments are optional:
@ -217,7 +209,6 @@ MAX-ENTRIES: The maximum number of posts to render in each feed"
((atom-feed #:file-name (string-append prefix "/" tag ".xml") ((atom-feed #:file-name (string-append prefix "/" tag ".xml")
#:subtitle (string-append "Tag: " tag) #:subtitle (string-append "Tag: " tag)
#:filter filter #:filter filter
#:max-entries max-entries #:max-entries max-entries)
#:blog-prefix blog-prefix)
site posts))) site posts)))
tag-groups)))) tag-groups))))

View File

@ -69,16 +69,12 @@
" — " ,(date->string* (post-date post))) " — " ,(date->string* (post-date post)))
(div ,(post-sxml post)))) (div ,(post-sxml post))))
(define (ugly-default-collection-template site title posts prefix) (define (ugly-default-collection-template site title posts)
(define (post-uri post)
(string-append (or prefix "") "/"
(site-post-slug site post) ".html"))
`((h3 ,title) `((h3 ,title)
(ul (ul
,@(map (lambda (post) ,@(map (lambda (post)
`(li `(li
(a (@ (href ,(post-uri post))) (a (@ (href ,(site-post-path site post)))
,(post-ref post 'title) ,(post-ref post 'title)
" — " " — "
,(date->string* (post-date post))))) ,(date->string* (post-date post)))))
@ -99,8 +95,8 @@
(body ((theme-post-template theme) post))) (body ((theme-post-template theme) post)))
(with-layout theme site title body))) (with-layout theme site title body)))
(define (render-collection theme site title posts prefix) (define (render-collection theme site title posts)
(let ((body ((theme-collection-template theme) site title posts prefix))) (let ((body ((theme-collection-template theme) site title posts)))
(with-layout theme site title body))) (with-layout theme site title body)))
(define (date->string* date) (define (date->string* date)
@ -117,25 +113,24 @@
(collections (collections
`(("Recent Posts" "index.html" ,posts/reverse-chronological)))) `(("Recent Posts" "index.html" ,posts/reverse-chronological))))
"Return a procedure that transforms a list of posts into pages "Return a procedure that transforms a list of posts into pages
decorated by THEME, whose URLs start with PREFIX." decorated by THEME. The collection listing URL starts with PREFIX, and
(define (make-file-name base-name) the individual posts URLs start with POST-PREFIX."
(define (make-file-name prefix base-name)
(if prefix (if prefix
(string-append prefix "/" base-name) (string-append prefix "/" base-name)
base-name)) base-name))
(lambda (site posts) (lambda (site posts)
(define (post->page post) (define (post->page post)
(let ((base-name (string-append (site-post-slug site post) (make-page (site-post-relative-path site post)
".html"))) (render-post theme site post)
(make-page (make-file-name base-name) sxml->html))
(render-post theme site post)
sxml->html)))
(define collection->page (define collection->page
(match-lambda (match-lambda
((title file-name filter) ((title file-name filter)
(make-page (make-file-name file-name) (make-page (make-file-name prefix file-name)
(render-collection theme site title (filter posts) prefix) (render-collection theme site title (filter posts))
sxml->html)))) sxml->html))))
(append (map post->page posts) (append (map post->page posts)

View File

@ -49,7 +49,7 @@
(display "<?xml version=\"1.0\" encoding=\"utf-8\"?>" port) (display "<?xml version=\"1.0\" encoding=\"utf-8\"?>" port)
(sxml->xml sxml port)) (sxml->xml sxml port))
(define* (post->rss-item site post #:key (blog-prefix "")) (define* (post->rss-item site post)
"Convert POST into an RSS <item> node." "Convert POST into an RSS <item> node."
`(item `(item
(title ,(post-ref post 'title)) (title ,(post-ref post 'title))
@ -64,8 +64,7 @@
(string-append "(" author ")") (string-append "(" author ")")
"")))) ""))))
(pubDate ,(date->rfc822-str (post-date post))) (pubDate ,(date->rfc822-str (post-date post)))
(link (@ (href ,(string-append blog-prefix "/" (link (@ (href ,(site-post-url site post))
(site-post-slug site post) ".html"))
(rel "alternate"))) (rel "alternate")))
(description ,(sxml->html-string (post-sxml post))) (description ,(sxml->html-string (post-sxml post)))
,@(map (lambda (enclosure) ,@(map (lambda (enclosure)
@ -82,8 +81,7 @@
(file-name "rss-feed.xml") (file-name "rss-feed.xml")
(subtitle "Recent Posts") (subtitle "Recent Posts")
(filter posts/reverse-chronological) (filter posts/reverse-chronological)
(max-entries 20) (max-entries 20))
(blog-prefix ""))
"Return a builder procedure that renders a list of posts as an RSS "Return a builder procedure that renders a list of posts as an RSS
feed. All arguments are optional: feed. All arguments are optional:
@ -101,7 +99,6 @@ MAX-ENTRIES: The maximum number of posts to render in the feed"
(description ,subtitle) (description ,subtitle)
(pubDate ,(date->rfc822-str (current-date))) (pubDate ,(date->rfc822-str (current-date)))
(link (@ (href ,(site-domain site)))) (link (@ (href ,(site-domain site))))
,@(map (cut post->rss-item site <> ,@(map (cut post->rss-item site <>)
#:blog-prefix blog-prefix)
(take-up-to max-entries (filter posts))))) (take-up-to max-entries (filter posts)))))
sxml->xml*))) sxml->xml*)))

View File

@ -33,32 +33,37 @@
#:use-module (haunt page) #:use-module (haunt page)
#:use-module (haunt post) #:use-module (haunt post)
#:use-module (haunt asset) #:use-module (haunt asset)
#:use-module (web uri)
#:export (site #:export (site
site? site?
site-title site-title
site-domain site-domain
site-scheme site-scheme
site-posts-directory site-posts-directory
site-posts-output-directory
site-file-filter site-file-filter
site-build-directory site-build-directory
site-default-metadata site-default-metadata
site-make-slug site-make-slug
site-readers site-readers
site-builders site-builders
site-post-slug site-post-path
site-post-relative-path
site-post-url
build-site build-site
make-file-filter make-file-filter
default-file-filter)) default-file-filter))
(define-record-type <site> (define-record-type <site>
(make-site title domain scheme posts-directory file-filter build-directory (make-site title domain scheme posts-directory posts-output-directory file-filter
default-metadata make-slug readers builders) build-directory default-metadata make-slug readers builders)
site? site?
(title site-title) (title site-title)
(domain site-domain) (domain site-domain)
(scheme site-scheme) ; https or http (scheme site-scheme) ; https or http
(posts-directory site-posts-directory) (posts-directory site-posts-directory)
(posts-output-directory site-posts-output-directory)
(file-filter site-file-filter) (file-filter site-file-filter)
(build-directory site-build-directory) (build-directory site-build-directory)
(default-metadata site-default-metadata) (default-metadata site-default-metadata)
@ -71,6 +76,7 @@
(domain "example.com") (domain "example.com")
(scheme 'https) (scheme 'https)
(posts-directory "posts") (posts-directory "posts")
(posts-output-directory "")
(file-filter default-file-filter) (file-filter default-file-filter)
(build-directory "site") (build-directory "site")
(default-metadata '()) (default-metadata '())
@ -83,6 +89,7 @@ TITLE: The name of the site
DOMAIN: The domain that will host the site DOMAIN: The domain that will host the site
SCHEME: Either 'https' or 'http' ('https' by default) SCHEME: Either 'https' or 'http' ('https' by default)
POSTS-DIRECTORY: The directory where posts are found POSTS-DIRECTORY: The directory where posts are found
POSTS-OUTPUT-DIRECTORY: The directory to store the built posts in
FILE-FILTER: A predicate procedure that returns #f when a post file FILE-FILTER: A predicate procedure that returns #f when a post file
should be ignored, and #f otherwise. Emacs temp files are ignored by should be ignored, and #f otherwise. Emacs temp files are ignored by
default. default.
@ -92,13 +99,33 @@ whose keys are symbols
MAKE-SLUG: A procedure generating a file name slug from a post MAKE-SLUG: A procedure generating a file name slug from a post
READERS: A list of reader objects for processing posts READERS: A list of reader objects for processing posts
BUILDERS: A list of procedures for building pages from posts" BUILDERS: A list of procedures for building pages from posts"
(make-site title domain scheme posts-directory file-filter build-directory (make-site title domain scheme posts-directory posts-output-directory file-filter
default-metadata make-slug readers builders)) build-directory default-metadata make-slug readers builders))
(define (site-post-slug site post) (define (site-post-slug site post)
"Return a slug string for POST using the slug generator for SITE." "Return a slug string for POST using the slug generator for SITE."
((site-make-slug site) post)) ((site-make-slug site) post))
(define (site-post-relative-path site post)
"Return a relative path to a POST, without the preceding slash `/'."
(let ((base-path (string-trim-right (site-posts-output-directory site)
(lambda (c) (equal? c #\/)))))
(string-append (if (equal? base-path "")
""
(string-append base-path "/"))
(site-post-slug site post)
".html")))
(define (site-post-path site post)
"Return a path to a POST, with the preceding slash `/'."
(string-append "/" (site-post-relative-path site post)))
(define (site-post-url site post)
"Return a full URL to a POST."
(build-uri (site-scheme site)
#:host (site-domain site)
#:path (site-post-path site post)))
(define (build-site site) (define (build-site site)
"Build SITE in the appropriate build directory." "Build SITE in the appropriate build directory."
(let ((posts (if (file-exists? (site-posts-directory site)) (let ((posts (if (file-exists? (site-posts-directory site))

View File

@ -117,11 +117,7 @@ culture works available under the " ,%cc-by-sa-link " license.")))))))
" — " ,(date->string* (post-date post))) " — " ,(date->string* (post-date post)))
(div ,(post-sxml post)))) (div ,(post-sxml post))))
#:collection-template #:collection-template
(lambda (site title posts prefix) (lambda (site title posts)
(define (post-uri post)
(string-append "/" (or prefix "")
(site-post-slug site post) ".html"))
`(,(jumbotron `(,(jumbotron
`((p "Haunt is a simple, functional, hackable static site `((p "Haunt is a simple, functional, hackable static site
generator written in Guile Scheme that gives authors the ability to generator written in Guile Scheme that gives authors the ability to
@ -164,7 +160,7 @@ without needing to upload the generated files to a web server.")
(ul (ul
,@(map (lambda (post) ,@(map (lambda (post)
`(li `(li
(a (@ (href ,(post-uri post))) (a (@ (href ,(site-post-path site post)))
,(post-ref post 'title) ,(post-ref post 'title)
" — " " — "
,(date->string* (post-date post))))) ,(date->string* (post-date post)))))