require "upath" require "proto" local asciidoc = Object:clone() -- set type=asciidoc metadata for path function asciidoc:register(path) assert(self.session:acl_check(path, "asciidoc"), "EACCESS:May not use asciidoc on path") self.session:meta_reset(path, "type", "type", "asciidoc") end function asciidoc:unregister(path) self.session:meta_delete(path, "type", "type", "asciidoc") end -- validate file -- return false will just ignore this type function asciidoc:check(path) assert((path:find("%.txt$")), "ERANGE:asciidoc files must end in .txt") return true end -- remove all dependency relations which where previously recorded for path function asciidoc:abolish(path) for _,dest in pairs(self.session:meta_get(path, "generates", "asciidoc")) do dump("abolish_test", path .. " generates " .. dest) for _,source in pairs(self.session:meta_get(dest, "requires", "asciidoc")) do dump("abolish_test", dest .. " requires " .. source) self.session:meta_delete(dest, "requires", "asciidoc", source) end self.session:meta_delete(path, "generates", "asciidoc", dest) end end function asciidoc:discover(path) -- first remove all existing dependencies self:abolish(path) -- dependencies for the generated file local generated = (path:match("(.*)%.txt$") or path) .. ".html" self.session:meta_new(generated, "requires", "asciidoc", path) self.session:meta_new(path, "generates", "asciidoc", generated) for line in io.lines(upath.localpath(uwiki_conf.prefix..uwiki_conf.docroot, path)) do for included in line:gmatch('include1?:+([^[]*)') do local prefixpath = path:match("/(.*/)") or "" local npath = upath.normalpath(uwiki_conf.prefix..uwiki_conf.docroot, prefixpath..included) self.session:meta_new(path, "requires", "asciidoc", npath) self.session:meta_new(npath, "generates", "asciidoc", path) end end -- TODO dependencies on conf file end -- compile path to destpath function asciidoc:compile(path, destpath) local opts = self.session:meta_get(path, "asciidoc", "opts") local lpath = upath.localpath(uwiki_conf.prefix..uwiki_conf.docroot, path) assert(os.execute( [[ asciidoc %opts% %localpath% ]] % { opts = (function () local str = "" for _,row in pairs(opts) do str = str .. (#row == 0 and '' or row .. " ") end return str end)(), localpath = lpath:sanitize('shquote') }) == 0, "ESYS:asciidoc failed") end -- figures out what kind of changes are from old to new (maybe with the help of scm) -- intended types (the exact interpretation is open to the type): -- "none" did not changed anything -- "edit" mixed edit -- "prepend" user prepended only -- "append" user appended only -- "add" only content added but nothing removed -- "comment" commented only -- "commentadd" added comment only -- "spam" detected spam -- currentfile the current file -- newfile the new file -- return a string describing the kind (required sub-permission), returning nil will not yield in a acl check and permit anything function asciidoc:diffkind(currentfile, newfile) local diff = io.popen("diff -d -C1 %old% %new%" % { old = currentfile:sanitize('shquote'), new = newfile:sanitize('shquote')}) local changestat = { comment = {added = 0, changed = 0}, content = {added = 0, changed = 0}, prepend = 'unknown', append = 'unknown', changes = 0 } for line in diff:lines() do local mode,content = line:match('^(.) (.*)') if mode then -- this pattern is slightly broken as it will detect empty comment lines (//) as content local kind = (content:find('^//[^/]')) and "comment" or "content" if mode == '+' then -- TODO rxpd spamcheck here, per kind? changestat[kind].added = changestat[kind].added + 1 changestat.changes = changestat.changes + 1 if changestat.prepend == 'unknown' then changestat.prepend = 'maybe' end if changestat.append == 'unknown' then changestat.append = 'maybe' end elseif mode == '!' then -- TODO rxpd spamcheck here, per kind? changestat[kind].changed = changestat[kind].changed + 1 changestat.changes = changestat.changes + 1 changestat.prepend = false changestat.append = false elseif mode == '-' then changestat[kind].changed = changestat[kind].changed + 1 changestat.changes = changestat.changes + 1 changestat.prepend = false changestat.append = false elseif mode == ' ' then if changestat.prepend == 'unknown' then changestat.prepend = false end if changestat.append == 'maybe' then changestat.append = false end end end end diff:close() -- now analyze the stats local result if changestat.changes == 0 then -- nothing changed result = 'none' else if changestat.content.added == 0 and changestat.content.changed == 0 then if changestat.comment.changed == 0 then -- only comments added result = 'commentadd' else -- edit in comment result = 'comment' end else if changestat.append == 'maybe' then -- only added new content at the end result = 'append' elseif changestat.prepend == 'maybe' then -- only added new content at the begin result = 'prepend' elseif changestat.content.changed == 0 then -- only new content added result = 'add' else -- generic edit result = 'edit' end end end return result end return asciidoc -- Local Variables: -- mode: lua -- lua-indent-level: 4 -- indent-tabs-mode: nil -- End: