diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/nimweb.nim | 120 | ||||
-rw-r--r-- | tools/website.tmpl | 5 |
2 files changed, 122 insertions, 3 deletions
diff --git a/tools/nimweb.nim b/tools/nimweb.nim index 27e843fde..c5d510eac 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -8,7 +8,8 @@ # import - os, strutils, times, parseopt, parsecfg, streams, strtabs, tables + os, strutils, times, parseopt, parsecfg, streams, strtabs, tables, + re, htmlgen, macros, md5 type TKeyValPair = tuple[key, id, val: string] @@ -19,6 +20,8 @@ type vars: PStringTable nimrodArgs: string quotations: TTable[string, tuple[quote, author: string]] + TRssItem = object + year, month, day, title: string proc initConfigData(c: var TConfigData) = c.tabs = @[] @@ -59,6 +62,38 @@ Compile_options: will be passed to the Nimrod compiler """ + rYearMonthDayTitle = r"(\d{4})-(\d{2})-(\d{2})\s+(.*)" + rssUrl = "http://nimrod-code.org/news.xml" + rssNewsUrl = "http://nimrod-code.org/news.html" + validAnchorCharacters = Letters + Digits + + +macro id(e: expr): expr {.immediate.} = + ## generates the rss xml ``id`` element. + let e = callsite() + result = xmlCheckedTag(e, "id") + +macro updated(e: expr): expr {.immediate.} = + ## generates the rss xml ``updated`` element. + let e = callsite() + result = xmlCheckedTag(e, "updated") + +proc updatedDate(year, month, day: string): string = + ## wrapper around the update macro with easy input. + result = updated("$1-$2-$3T00:00:00Z" % [year, + repeatStr(2 - len(month), "0") & month, + repeatStr(2 - len(day), "0") & day]) + +macro entry(e: expr): expr {.immediate.} = + ## generates the rss xml ``entry`` element. + let e = callsite() + result = xmlCheckedTag(e, "entry") + +macro content(e: expr): expr {.immediate.} = + ## generates the rss xml ``content`` element. + let e = callsite() + result = xmlCheckedTag(e, "content", reqAttr = "type") + proc parseCmdLine(c: var TConfigData) = var p = initOptParser() while true: @@ -207,6 +242,85 @@ proc buildAddDoc(c: var TConfigData, destPath: string) = Exec("nimrod doc $# -o:$# $#" % [c.nimrodArgs, destPath / changeFileExt(splitFile(d).name, "html"), d]) +proc parseNewsTitles(inputFilename: string): seq[TRssItem] = + # parses the file for titles and returns them as TRssItem blocks. + let reYearMonthDayTitle = re(rYearMonthDayTitle) + var + input: TFile + line = "" + + result = @[] + if not open(input, inputFilename): + quit("Could not read $1 for rss generation" % [inputFilename]) + finally: input.close() + while input.readline(line): + if line =~ reYearMonthDayTitle: + result.add(TRssItem(year: matches[0], month: matches[1], day: matches[2], + title: matches[3])) + +proc genUUID(text: string): string = + # Returns a valid RSS uuid, which is basically md5 with dashes and a prefix. + result = getMD5(text) + result.insert("-", 20) + result.insert("-", 16) + result.insert("-", 12) + result.insert("-", 8) + result.insert("urn:uuid:") + +proc genNewsLink(title: string): string = + # Mangles a title string into an expected news.html anchor. + result = title + result.insert("Z") + for i in 1..len(result)-1: + let letter = result[i].toLower() + if letter in validAnchorCharacters: + result[i] = letter + else: + result[i] = '-' + result.insert(rssNewsUrl & "#") + +proc generateRss(outputFilename: string, news: seq[TRssItem]) = + # Given a list of rss items generates an rss overwriting destination. + var + output: TFile + + if not open(output, outputFilename, mode = fmWrite): + quit("Could not write to $1 for rss generation" % [outputFilename]) + finally: output.close() + + output.write("""<?xml version="1.0" encoding="utf-8"?> +<feed xmlns="http://www.w3.org/2005/Atom"> +""") + output.write(title("Nimrod website news")) + output.write(link(href = rssUrl, rel = "self")) + output.write(link(href = rssNewsUrl)) + output.write(id(rssNewsUrl)) + + let now = getGMTime(getTime()) + output.write(updatedDate($now.year, $(int(now.month) + 1), $now.monthday)) + + for rss in news: + let joinedTitle = "$1-$2-$3 $4" % [rss.year, rss.month, rss.day, rss.title] + output.write(entry( + title(joinedTitle), + id(genUUID(joinedTitle)), + link(`type` = "text/html", rel = "alternate", + href = genNewsLink(joinedTitle)), + updatedDate(rss.year, rss.month, rss.day), + "<author><name>Nimrod</name></author>", + content(joinedTitle, `type` = "text"), + )) + + output.write("""</feed>""") + +proc buildNewsRss(c: var TConfigData, destPath: string) = + # generates an xml feed from the web/news.txt file + let + srcFilename = "web" / "news.txt" + destFilename = destPath / changeFileExt(splitFile(srcFilename).name, "xml") + + generateRss(destFilename, parseNewsTitles(srcFilename)) + proc main(c: var TConfigData) = const cmd = "nimrod rst2html --compileonly $1 -o:web/$2.temp web/$2.txt" @@ -217,6 +331,7 @@ proc main(c: var TConfigData) = quit("[Error] cannot open: " & c.ticker) for i in 0..c.tabs.len-1: var file = c.tabs[i].val + let rss = if file in ["news", "index"]: extractFilename(rssUrl) else: "" Exec(cmd % [c.nimrodArgs, file]) var temp = "web" / changeFileExt(file, "temp") var content: string @@ -229,12 +344,13 @@ proc main(c: var TConfigData) = if not existsDir("web/upload"): createDir("web/upload") if open(f, outfile, fmWrite): - writeln(f, generateHTMLPage(c, file, content)) + writeln(f, generateHTMLPage(c, file, content, rss)) close(f) else: quit("[Error] cannot write file: " & outfile) removeFile(temp) copyDir("web/assets", "web/upload/assets") + buildNewsRss(c, "web/upload") buildAddDoc(c, "web/upload") buildDoc(c, "web/upload") buildDoc(c, "doc") diff --git a/tools/website.tmpl b/tools/website.tmpl index 0ec659267..091079c1c 100644 --- a/tools/website.tmpl +++ b/tools/website.tmpl @@ -1,5 +1,5 @@ #! stdtmpl | standard -#proc generateHTMLPage(c: var TConfigData, currentTab, content: string): string = +#proc generateHTMLPage(c: var TConfigData, currentTab, content, rss: string): string = # result = "" <!doctype html> <html> @@ -8,6 +8,9 @@ <title>$c.projectTitle</title> <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" /> <link rel="stylesheet" type="text/css" href="assets/style.css" /> + #if len(rss) > 0: + <link href="$rss" title="Recent changes" type="application/atom+xml" rel="alternate"> + #end fi </head> <body> |