all repos — hastysite @ 85e13f4f5f14ba66d8e373c40c4c1c0966cc48e7

A high-performance static site generator.

Now checking for modified assets as well and saving metadata of modified
files.
h3rald h3rald@h3rald.com
Sat, 05 Nov 2016 21:34:06 +0100
commit

85e13f4f5f14ba66d8e373c40c4c1c0966cc48e7

parent

3ddd11ac77ca65524207ee0d6717660982c99269

1 files changed, 100 insertions(+), 102 deletions(-)

jump to
M hastysite.nimhastysite.nim

@@ -21,7 +21,7 @@ type

HastyDirs = object assets*: string contents*: string - layouts*: string + templates*: string output*: string temp*: string tempContents: string

@@ -29,7 +29,7 @@ HastyFiles = object

rules*: string metadata: string checksums: string - modified: seq[string] + modified: seq[JsonNode] HastySite* = object settings*: JsonNode metadata*: JsonNode

@@ -39,95 +39,9 @@ NoMetadataException* = ref Exception

DictionaryRequiredException* = ref Exception -#### MiNiM Library - -proc hastysite_module*(i: In, hs: HastySite) = - i.define("hastysite") - - .symbol("metadata") do (i: In): - i.push i.fromJson(hs.metadata) - - .symbol("mget") do (i: In): - var s: MinValue - i.reqStringLike s - i.push i.fromJson(hs.metadata[s.getString]) - - .symbol("mset") do (i: In): - var s: MinValue - i.reqStringLike s - let v = i.pop - hs.metadata[s.getString] = %v - - .symbol("settings") do (i: In): - i.push i.fromJson(hs.settings) - - .symbol("sget") do (i: In): - var s: MinValue - i.reqStringLike s - i.push i.fromJson(hs.settings[s.getString]) - - .symbol("sset") do (i: In): - var s: MinValue - i.reqStringLike s - let v = i.pop - hs.settings[s.getString] = %v - - .symbol("modified") do (i: In): - var modified = newSeq[MinValue](0) - for s in hs.files.modified: - modified.add s.newVal - i.push modified.newVal(i.scope) - - .symbol("init-context") do (i: In): - var d: MinValue - i.reqDictionary d - i.scope.symbols["context"] = MinOperator(val: d, kind: minValOp) - - .symbol("output") do (i: In): - i.push hs.dirs.output.newVal - - .symbol("cget") do (i: In): - var s, q: MinValue - i.reqStringLike(s) - i.apply(i.scope.getSymbol("context")) - i.reqDictionary q - i.push q.dget(s) - - .symbol("cset") do (i: In): - var q, k: MinValue - let m = i.pop - i.reqStringLike k - i.apply(i.scope.getSymbol("context")) - i.reqDictionary q - i.dset(q, k, m) - - .symbol("mustache") do (i: In): - var t, c: MinValue - i.reqQuotationAndString c, t - if not c.isDictionary: - raise DictionaryRequiredException(msg: "No dictionary provided as template context.") - let ctx = newContext(%c) - let tplname = t.getString & ".mustache" - let tpl = readFile(hs.dirs.layouts/tplname) - i.push tpl.render(ctx, hs.dirs.layouts).newval - - .symbol("markdown") do (i: In): - var t, c: MinValue - i.reqQuotationAndString c, t - if not c.isDictionary: - raise DictionaryRequiredException(msg: "No dictionary provided for markdown processor fields.") - let options = HastyOptions(toc: false, output: nil, css: nil, watermark: nil, fragment: true) - var fields = initTable[string, proc():string]() - for items in c.qVal: - fields[c.qVal[0].getString] = proc(): string = return $$c.qVal[1] - var hastyscribe = newHastyScribe(options, fields) - i.push hastyscribe.compileFragment(t.getString).newVal - - .finalize() - #### Helper Functions -proc preprocessFile(file, dir: string, obj: var JsonNode): string = +proc preprocessContent(file, dir: string, obj: var JsonNode): string = let fileid = file.replace(dir, "") var f: File discard f.open(file)

@@ -149,10 +63,9 @@ obj["contents"] = newJObject()

obj["contents"][fileid] = yaml.loadToJson()[0] f.close() -proc checkFile(file, dir: string, obj: var JsonNode): bool = +proc checkContent(dir, file: string, obj: var JsonNode): bool = + var dir = dir & DirSep let fileid = file.replace(dir, "") - if not obj.hasKey("contents"): - obj["contents"] = newJObject() var oldChecksum = "" if obj["contents"].hasKey(fileid): oldChecksum = obj["contents"][fileid].getStr

@@ -160,6 +73,16 @@ var newChecksum = $secureHashFile(file)

obj["contents"][fileid] = %newChecksum return oldChecksum != newChecksum +proc checkAsset(dir, file: string, obj: var JsonNode): bool = + var dir = dir & DirSep + let fileid = file.replace(dir, "") + var oldChecksum = "" + if obj["assets"].hasKey(fileid): + oldChecksum = obj["assets"][fileid].getStr + var newChecksum = $secureHashFile(file) + obj["assets"][fileid] = %newChecksum + return oldChecksum != newChecksum + proc get(json: JsonNode, key, default: string): string = if json.hasKey(key): return json[key].getStr

@@ -175,6 +98,33 @@ proc quitIfNotExists(file: string) =

if not file.fileExists: quit("Error: File '$1' not found." % file) +proc initChecksums(hs: HastySite): JsonNode = + if not hs.files.checksums.fileExists: + hs.files.checksums.writeFile("{}") + result = hs.files.checksums.parseFile() + if not result.hasKey("contents"): + result["contents"] = newJObject() + if not result.hasKey("assets"): + result["assets"] = newJObject() + +proc contentMetadata(f, dir: string, meta: JsonNode): JsonNode = + result = newJObject() + var fdata = f.splitFile + for key, value in meta["contents"][result["path"].getStr].pairs: + result[key] = value + result["path"] = %f.replace(dir & DirSep, "") + result["type"] = %"content" + result["id"] = %fdata.dir.joinPath(fdata.name) + result["ext"] = %fdata.ext + +proc assetMetadata(f, dir: string): JsonNode = + result = newJObject() + var fdata = f.splitFile + result["path"] = %f.replace(dir & DirSep, "") + result["type"] = %"asset" + result["id"] = %fdata.dir.joinPath(fdata.name) + result["ext"] = %fdata.ext + #### Main Functions proc newHastySite*(file: string): HastySite =

@@ -182,7 +132,7 @@ let json = file.parseFile()

result.settings = json result.dirs.assets = json.get("assets", "assets") result.dirs.contents = json.get("contents", "contents") - result.dirs.layouts = json.get("layouts", "layouts") + result.dirs.templates = json.get("templates", "templates") result.dirs.output = json.get("output", "output") result.dirs.temp = json.get("temp", "temp") result.dirs.tempContents = result.dirs.temp / result.dirs.contents

@@ -193,27 +143,32 @@

proc preprocess*(hs: HastySite) = var meta = newJObject() for f in hs.dirs.contents.walkDirRec(): - let content = f.preprocessFile(hs.dirs.contents & DirSep, meta) + let content = f.preprocessContent(hs.dirs.contents & DirSep, meta) let dest = hs.dirs.temp/f dest.parentDir.createDir dest.writeFile(content) hs.files.metadata.writeFile(meta.pretty) proc detectChanges*(hs: var HastySite) = - hs.files.modified = newSeq[string](0) - if not hs.files.checksums.fileExists: - hs.files.checksums.writeFile("{}") - var cs = hs.files.checksums.parseFile() - let files = toSeq(hs.dirs.tempContents.walkDirRec()) - let dir = hs.dirs.tempContents - hs.files.modified = filter(files) do (f: string) -> bool: f.checkFile(dir & DirSep, cs) + hs.files.modified = newSeq[JsonNode](0) + var cs = hs.initChecksums() + let contents = toSeq(hs.dirs.tempContents.walkDirRec()) + let assets = toSeq(hs.dirs.assets.walkDirRec()) + let assetDir = hs.dirs.assets + let contentDir = hs.dirs.tempContents + let meta = hs.metadata + let modContentFiles = filter(contents) do (f: string) -> bool: checkContent(contentDir, f, cs) + let modAssetFiles = filter(assets) do (f: string) -> bool: checkAsset(assetDir, f, cs) + let modContents = modContentFiles.map(proc (f: string): JsonNode = return contentMetadata(f, contentDir, meta)) + let modAssets = modAssetFiles.map(proc (f: string): JsonNode = return assetMetadata(f, assetDir)) + hs.files.modified = modContents & modAssets hs.files.checksums.writeFile(cs.pretty) proc init*(dir: string) = var json = newJObject() json["contents"] = %"contents" json["assets"] = %"assets" - json["layouts"] = %"layouts" + json["templates"] = %"templates" json["temp"] = %"temp" json["output"] = %"output" for key, value in json.pairs:

@@ -233,7 +188,50 @@ hs.detectChanges()

# TODO echo hs.files.modified +#### MiNiM Library +proc hastysite_module*(i: In, hs: HastySite) = + i.define("hastysite") + + .symbol("metadata") do (i: In): + i.push i.fromJson(hs.metadata) + + .symbol("settings") do (i: In): + i.push i.fromJson(hs.settings) + + .symbol("modified") do (i: In): + var modified = newSeq[MinValue](0) + for j in hs.files.modified: + modified.add i.fromJson(j) + i.push modified.newVal(i.scope) + + .symbol("output") do (i: In): + i.push hs.dirs.output.newVal + + .symbol("mustache") do (i: In): + var t, c: MinValue + i.reqQuotationAndString c, t + if not c.isDictionary: + raise DictionaryRequiredException(msg: "No dictionary provided as template context.") + let ctx = newContext(%c) + let tplname = t.getString & ".mustache" + let tpl = readFile(hs.dirs.templates/tplname) + i.push tpl.render(ctx, hs.dirs.templates).newval + + .symbol("markdown") do (i: In): + var t, c: MinValue + i.reqQuotationAndString c, t + if not c.isDictionary: + raise DictionaryRequiredException(msg: "No dictionary provided for markdown processor fields.") + let options = HastyOptions(toc: false, output: nil, css: nil, watermark: nil, fragment: true) + var fields = initTable[string, proc():string]() + for items in c.qVal: + fields[c.qVal[0].getString] = proc(): string = return $$c.qVal[1] + var hastyscribe = newHastyScribe(options, fields) + i.push hastyscribe.compileFragment(t.getString).newVal + + .finalize() + when isMainModule: import