(module blogue mzscheme
(require (lib "unitsig.ss")
(lib "list.ss")
(lib "file.ss")
(lib "struct.ss")
(lib "plt-match.ss"))
(require (planet "list.ss" ("jaymccarthy" "mmss.plt" 1))
(planet "xml.ss" ("jaymccarthy" "mmss.plt" 1))
(planet "date.ss" ("jaymccarthy" "mmss.plt" 1)))
(require "blogue-post.ss"
"blogue-world.ss"
"blogue-sig.ss")
(provide build-site)
(define (Month->MonthName M)
(month-name/number (string->number M)))
(define (build-site config@)
(define site@
(compound-unit/sig
(import)
(link (CONFIG : blogue-config^ (config@))
(CORE : blogue^ (blogue@ CONFIG)))
(export)))
(invoke-unit/sig site@))
(define blogue@
(unit/sig blogue^
(import blogue-config^)
(define (gen-Post-FXexpr p)
(let ([Body (Post-Content p)]
[Permapath (Post-Permapath p)])
(EntryTemplate Permapath
(Post-Date-tm p)
(map bytes->string/utf-8 (Post-Category p))
(Post-Title p)
(let loop ([I Body] [x 1] [R '()])
(if (null? I) R
(let ([c (car I)])
(if (and (list? c) (not (null? c)) (eq? (car c) 'p))
(loop (cdr I) (+ x 1)
(let ([p-id (string-append "e" (regexp-replace "Post" (regexp-replace* "/" (Post-Id p) "") "")
"p" (number->string x))])
(append R
`( (p ([id ,p-id])
,@(cddr c)
(a ([class "pglink"] [href ,(string-append Permapath "/#" p-id)]) "#")) ))))
(loop (cdr I) x (append R (list c))))))))))
(define (format-Post! w pi)
(let ([p (World-Post w pi)])
(when (eq? (Post-FXexpr p) 'error)
(set-World-Post! w (copy-struct Post p [Post-FXexpr (gen-Post-FXexpr p)])))
w))
(define (format-year w Y)
`(ul
,@(map (lambda (M)
`(li (a ([href ,(format "/Archives/~a/~a" Y M)]) ,(Month->MonthName M))))
(reverse (World-DateMap-Year/Months w Y)))))
(define (format-calendar w Y M Previous Next)
(let ([Mn (Month->MonthName M)]
[Date->Month (lambda (D) (match-let ([(list _ Year Month) (regexp-match "(....)/(..)" D)]) Month))])
`(table ([class "calendar"])
(tr (td ([class "label"] [colspan "7"]) ,Mn " " ,Y))
(tr ([class "header"])
(td "Sun") (td "Mon") (td "Tue") (td "Wed") (td "Thu") (td "Fri") (td "Sat"))
,@(map (lambda (week)
`(tr ,@(map (lambda (day-n)
(if (not (number? day-n))
`(td)
`(td ,(let* ([sday (number->string day-n)]
[day (if (< day-n 10) (string-append "0" sday) sday)])
(if (World-DateMap-Year/Month/Day-Posts? w Y M day)
`(a ([href ,(format "/Archives/~a/~a/~a" Y M day)]) ,day)
day)))))
week)))
(generate-calendar (string->number Y) (string->number M)))
(tr ([class "footer"])
(td ([colspan "7"])
,@(if Previous
`((a ([href ,(format "/Archives/~a" Previous)]) ,(Month->MonthName (Date->Month Previous))))
`(nbsp nbsp nbsp))
nbsp
,@(if Next
`((a ([href ,(format "/Archives/~a" Next)]) ,(Month->MonthName (Date->Month Next))))
`(nbsp nbsp nbsp)))))))
(define (format-category w Category Subcategories Posts)
`((div ([id "subcategories"])
(ul ,@(map (lambda (Child)
`(li (a ([href ,(string-append "/Categories" Child)]) ,Child)))
(quicksort (map bytes->string/utf-8 Subcategories) string<?))))
,@(map (lambda (pi) (Post-FXexpr (World-Post w pi)))
(list-head (quicksort Posts string>?) PostsInCategory))))
(define (write-template! Path Title Previous Next DisplayAds Body)
(let* ([DirPath (build-path BuildRoot Path)]
[Previous (if (not Previous) #f
(string-append "/Archives/" (regexp-replace "^/(Archives|Post)/" Previous "")))]
[Next (if (not Next) #f
(string-append "/Archives/" (regexp-replace "^/(Archives|Post)/" Next "")))])
(printf "~a => ~a~n" DirPath Title)
(write-xml! (build-path DirPath "index.html")
(MainTemplate Title Previous Next DisplayAds Body))))
(define (write-Post! w Previous pi Next)
(let ([p (World-Post w pi)])
(write-template! (apply build-path "Archives" (list-tail (explode-path (Post-Id p)) 2))
(Post-PageTitle p)
Previous Next #t
`(,(Post-FXexpr p)))))
(define (main)
(let ([w (load-World PostRoot format-Post!)])
(for-each/triple
(lambda (Previous pi Next)
(write-Post! w Previous pi Next))
(World-DateMap-Posts w))
(write-template! (build-path "Archives")
(list "Archives") #f #f #f
`((ul
,@(map (lambda (Year)
`(li (a ([href ,(format "/Archives/~a" Year)]) ,Year)
,(format-year w Year)))
(World-DateMap-Years w)))))
(for-each/triple (lambda (Previous Year Next)
(write-template! (build-path "Archives" Year)
(list Year) Previous Next #f
`(,(format-year w Year))))
(World-DateMap-Years w))
(for-each/triple (lambda (Previous Date Next)
(match-let ([(list _ Year Month) (regexp-match "(....)/(..)" Date)])
(write-template! (build-path "Archives" Year Month)
(list (Month->MonthName Month) " " Year) Previous Next #f
`((div ([id "monthview"])
,(format-calendar w Year Month Previous Next))))))
(World-DateMap-Months w))
(let ([Days (World-DateMap-Days w)])
(define (Date->Entries D)
(match-let ([(list _ Year Month Day) (regexp-match "(....)/(..)/(..)" D)])
(map (lambda (pi) (World-Post w pi))
(World-DateMap-Year/Month/Day-Posts w Year Month Day))))
(for-each/triple (lambda (Previous Date Next)
(match-let ([(list _ Year Month Day) (regexp-match "(....)/(..)/(..)" Date)])
(write-template!
(build-path "Archives" Year Month Day)
(list (Month->MonthName Month) " " Day ", " Year)
Previous Next #t
(map Post-FXexpr (reverse (Date->Entries Date))))))
Days)
(for-each/World-Category
(lambda (Category Subcategories Posts)
(let ([path (if (equal? #"/" Category)
(build-path "Categories")
(build-path "Categories" (bytes->path (subbytes Category 1 (bytes-length Category)))))])
(write-template! path
(map bytes->string/utf-8 (between #" > " (map path->bytes (rest (explode-path (build-path "/" path))))))
#f #f #t
(format-category w Category Subcategories Posts))))
w)
(let ([LastXDays (reverse (list-tail Days (max 0 (- (length Days) DaysInRSS))))])
(copy-file (build-path BuildRoot "Archives" (car LastXDays) "index.html") (build-path BuildRoot "index.html"))
(printf "Generating RSS...~n")
(let ([RSSEntries (apply append (map reverse (map Date->Entries LastXDays)))])
(write-xml! (build-path BuildRoot "RSS" "index.atom")
(Atom/2005 RSSEntries))
(write-xml! (build-path BuildRoot "RSS" "index.rss")
(RSS/0.91 RSSEntries))
(write-xml! (build-path BuildRoot "RSS" "index.xml")
(RSS/2.0 RSSEntries)))))
))
(define (main/files)
(when (directory-exists? BuildRoot)
(delete-directory/files BuildRoot))
(make-directory* BuildRoot)
(for-each
(lambda (Path)
(make-file-or-directory-link Path
(build-path BuildRoot (file-name-from-path Path))))
Link)
(main))
(main/files)
)))