Sun, 13 Sep 2009 22:22:47 +0300
Improvements
--- a/config.lua Sat Sep 12 21:27:57 2009 +0300 +++ b/config.lua Sun Sep 13 22:22:47 2009 +0300 @@ -3,3 +3,4 @@ dirsep = "/" meta_marker = "^---%s*$" +debug=true
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dependency.lua Sun Sep 13 22:22:47 2009 +0300 @@ -0,0 +1,18 @@ + +module("dependency", package.seeall) + +require('lfs') + +function simple_update_check(tgt, srcs) + local a=lfs.attributes(tgt) + if not a then + return true + end + for _, src in ipairs(srcs) do + local b=lfs.attributes(src) + if not b or b.modification > a.modification then + return true + end + end + return false +end
--- a/environment.lua Sat Sep 12 21:27:57 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ - -local hierarchy={} - -local function descend(hierarchy, dir) - local loca=hierarchy - string.gsub(dir, "([^/]+)", - function(d) - loca=hierarchy[d] - assert(loca) - end) - return loca -end - --- Tai sit vaan jokainen dokumentti ilman extensiota. - -function get_shortcuts(dir) - --local loca=descend(hierarchy, dir) - return {} --append(loca, append(hierarchy, {})) -end - -function get_environment(dir) - return { - location=dir, - shortcuts=get_shortcuts(dir) - } -end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/filecache.lua Sun Sep 13 22:22:47 2009 +0300 @@ -0,0 +1,13 @@ + +module("filecache", package.seeall) + +local cache={} + +function get(file) + if not cache[file] then + local f=io.openX(file, "r") + cache[file]=f:read('*a') + f:close() + end + return cache[file] +end
--- a/handlers.lua Sat Sep 12 21:27:57 2009 +0300 +++ b/handlers.lua Sun Sep 13 22:22:47 2009 +0300 @@ -6,14 +6,14 @@ require("handlers.ignore") local available={ - { pattern = "%.page$", handler = handlers.render}, - { pattern = "", handler = handlers.copy}, + { pattern = "%.lg$", handler = handlers.render}, + { pattern = "", handler = handlers.copy}, } function find(f) for _, h in ipairs(available) do - if string.match(h.pattern, f) then + if string.match(f, h.pattern) then return h.handler end end
--- a/handlers/copy.lua Sat Sep 12 21:27:57 2009 +0300 +++ b/handlers/copy.lua Sun Sep 13 22:22:47 2009 +0300 @@ -1,9 +1,25 @@ module("handlers.copy", package.seeall) -function phase1(f, env) +require("dependency") +require("log") + +function phase1(file, env) end -function phase2(f, env) - -- copy here! +function phase2(file, env) + local src=path.join(env.paths.src, file) + local dst=path.join(env.paths.dst, file) + if dependency.simple_update_check(dst, {src}) then + log.log("Copy "..file.."\n") + local f = io.openX(src, 'r') + local dstf = io.openX(dst, 'w') + while true do + local data=f:read(1024*1024) + if not data then + break + end + dstf:write(data) + end + end end
--- a/handlers/render.lua Sat Sep 12 21:27:57 2009 +0300 +++ b/handlers/render.lua Sun Sep 13 22:22:47 2009 +0300 @@ -1,25 +1,23 @@ module("handlers.render", package.seeall) +local ltp=require('ltp.template') require('markdown') -require('etree') -require('err') -require('environment') require('config') +require('path') +require('filecache') +require('log') -- -- Phase 1: load & markup -- -local phase1_cache={} - function phase1(file, env) - --local dir = string.match(file, "(.*)/[^/]*") - --local env = get_environment(dir) - local f = io.open(file, 'r') - local data = '' + local f = io.open(path.join(env.paths.src, file), 'r') + local data = nil local in_meta = false local linenum=1 + local meta = {} for l in f:lines() do if string.match(l, config.meta_marker) then @@ -27,78 +25,102 @@ elseif in_meta then local key, val = string.match(l, "%s*([^:]*)%s*:%s*(.*)%s*") if key and val then - env[key] = val + -- very primitive quoting, primarily as a hack to + -- not need converting my files that much from Webgen. + local val_unq=string.match(val, '^"(.*)"$') + meta[key] = val_unq or val else err.file_pos(file, linenum, "meta data syntax error") end else - data = data.."\n"..l + if data then + data = data.."\n"..l + elseif not string.match(l, "%s") then + data=l + end end linenum = linenum+1 end + log.log("Load "..file.."\n") + f:close() - local data2=markdown(data) + local destination + if meta.destination then + destination=path.join(path.dirname(file), meta.destination) + else + destination=path.rmext(file) + end + + local page={ + data=data, + meta=meta, + destination=destination, + file=file, + } - phase1_cache[file]=data2 + env.pages[file]=page end - --- --- Phase 2: Tag processing --- - --- Vaiko silti toistepäin? Inlinejen tagit pitää --- prosessoida ennen inlinetystä. Mutta toisaalta --- templateen myös prosessointi. - -local function tag_lgen_inline(env, t) - a.tag="div" - -- todo: get inlineable stuff from attrs - a.attr.class="lgen:inline" - --table.insert(a, get_inline(env, a) +function process_lua(template, env) + env=table.join(env, {env=env}) -- TODO: should use __index + --return ltp.render(nil, 1, template, env, {}, "<%", "%>", {}) + return ltp.render_template(template, "<%", "%>", + ltp.merge_index(env, _G)) end -local function tag_lgen_a(env, t) +function env_for(file, env, path_prefix) + local newenv=table.copy(env) + + newenv.base_url=path.to_root(file) + newenv.path_prefix=(path_prefix or "") + newenv.page=env.pages[file] + + return newenv end - -local operations={ - ["lgen:inline"] = tag_lgen_inline, - ["a"] = tag_lgen_a, -} - -local function scan(env, et) - for _, v in ipairs(et) do - if type(v)=="table" then - operations[v.tag](env, v) - end +function render(file, env, path_prefix) + local data=env.pages[file].data + if data then + local newenv=env_for(file, env, path_prefix) + local data2=process_lua(data, newenv) + return markdown(data2) end end -setmetatable(operations, { __index = function() return scan end }) - function phase2(file, env) - local data=phase1_cache[file] - --print(data) - --print("----------") - local et, msg, line, col, pos = etree.fromstring([[<!DOCTYPE html - PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><body>]]..data..'</body></html>') - --local et, msg, line, col, pos = lom.parse("<foo>"..data.."</foo>") - if not et then - error(string.format("%d:%d(%d): %s", line or -1 , col or -1, pos or -1, msg)) + local page=env.pages[file] + local src = path.join(env.paths.src, file) + local dst = path.join(env.paths.dst, page.destination) + local tmpl = path.join(env.paths.tmpl, + page.meta.template or "page.template") + local deps = {src} + + local build=page.meta.always_build + if not build then + if page.meta.dependencies then + for p, _ in pairs(env.pages) do + if string.match(page.meta.dependencies, p) then + table.insert(deps, path.join(env.paths.src, p)) + end + end + end + table.insert(deps, tmpl) + build=dependency.simple_update_check(dst, deps) end - operations[et.tag](env, et) - - -- TODO: inlining - -- maybe - --phase2_cache[file]=etree.tostring(et); + if build then + log.log("Render "..file.."\n") + local content=render(file, env) + local page_template=filecache.get(tmpl) + + local newenv=table.join({content=content}, env_for(file, env)) + local data2=process_lua(page_template, newenv) + + log.log("Write "..page.destination.."\n") + local f=io.openX(dst, "w") + f:write(data2) + end end - - -function phase3(file, env) -end
--- a/lgen.lua Sat Sep 12 21:27:57 2009 +0300 +++ b/lgen.lua Sun Sep 13 22:22:47 2009 +0300 @@ -4,27 +4,46 @@ require('scan') require('handlers') +-- globally add missing stuff +require('luaext') -- -- Main -- -if #arg < 2 then - error("Usage: lgen src dst") +if #arg < 3 then + error("Usage: lgen src tmpl dst") end src = arg[1] -dst = arg[2] +tmpl = arg[2] +dst = arg[3] print('Scan...') hierarchy = scan.scan(src) + +local env={ + paths={ + src=src, + dst=dst, + tmpl=tmpl, + }, + pages={ + }, +} + + -- Pitäisi env konstruoida. polun perusteella. scan.map(hierarchy, function(f) handlers.choose(f, env) end) print('Phase 1...') scan.map(hierarchy, function(f) handlers.phase1(f, env) end) print('Phase 2...') -scan.map(hierarchy, function(f) handlers.phase2(f, env) end) -print('Phase 3...') -scan.map(hierarchy, function(f) handlers.phase3(f, env) end) +scan.map(hierarchy, function(f) handlers.phase2(f, env) end, + function(d) + --log.log("Make path "..path.join(dst, d).."\n") + lfs.mkdir(path.join(dst, d)) + end) +--print('Phase 3...') +--scan.map(hierarchy, function(f) handlers.phase3(f, env) end)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/log.lua Sun Sep 13 22:22:47 2009 +0300 @@ -0,0 +1,10 @@ + +module("log", package.seeall) + +require("config") + +function log(str) + if config.debug then + io.stderr:write(str) + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ltp/LICENSE Sun Sep 13 22:22:47 2009 +0300 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ltp/README Sun Sep 13 22:22:47 2009 +0300 @@ -0,0 +1,18 @@ +This software is licensed under the Apache License 2.0 as described in +the LICENSE and NOTICE files. + +To configure and install: + + mkdir build + cd build + ../configure --prefix=INSTALL_DIR + make install + +INSTALL_DIR is the directory where you decide to install the software +such as /usr or /opt/ltp-x.x.x. + +The software requires Lua 5.1.3. + +At the moment, the only documentation available is contained in the +man page, but more examples and a basic tutorial will be published +with successive releases.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ltp/template.lua Sun Sep 13 22:22:47 2009 +0300 @@ -0,0 +1,192 @@ +-- +-- Copyright 2007-2008 Savarese Software Research Corporation. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.savarese.com/software/ApacheLicense-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +local ltp = require('ltp.util') + +local function compile_template_to_table(result, data, start_lua, end_lua) + local LF, CR, EQ = 10, 13, 61 + local i1, i2, i3 + + i3 = 1 + + repeat + i2, i1 = data:find(start_lua, i3, true) + + if i2 then + if i3 < i2 then + table.insert(result, "table.insert(output,") + table.insert(result, string.format('%q', data:sub(i3, i2 - 1))) + table.insert(result, ");") + end + + i1 = i1 + 2 + i2, i3 = data:find(end_lua, i1, true) + + if i2 then + if data:byte(i1-1) == EQ then + table.insert(result, "table.insert(output,") + table.insert(result, data:sub(i1, i2 - 1)) + table.insert(result, ");") + i3 = i3 + 1 + else + table.insert(result, data:sub(i1, i2 - 1)) + i3 = i3 + 1 + if data:byte(i3) == LF then + i3 = i3 + 1 + elseif data:byte(i3) == CR and data:byte(i3+1) == LF then + i3 = i3 + 2 + end + end + end + elseif i3 <= #data then + table.insert(result, "table.insert(output,") + table.insert(result, string.format('%q', data:sub(i3))) + table.insert(result, ");") + end + until not i2 + + return result +end + +local function compile_template_as_function(data, start_lua, end_lua) + local result = { "return function(output) " } + table.insert(compile_template_to_table(result, data, start_lua, end_lua), + "end") + return table.concat(result) +end + +local function compile_template(data, start_lua, end_lua) + return + table.concat(compile_template_to_table({ }, data, start_lua, end_lua)) +end + +local function load_template(data, start_lua, end_lua) + return + assert(loadstring(compile_template_as_function(data, start_lua, end_lua), + "=(load)"))() +end + +local function execute_template(template, environment, output) + setfenv(template, environment)(output) +end + +local function basic_environment(merge_global, environment) + if not environment then + environment = { } + end + + if merge_global then + ltp.merge_index(environment, _G) + else + environment.table = table + end + + return environment +end + +local function load_environment(env_files, merge_global) + local environment = nil + + if env_files and #env_files > 0 then + for i = 1,#env_files,1 do + local efun = assert(loadfile(env_files[i])) + + if i > 1 then + environment = ltp.merge_table(setfenv(efun, environment)(), environment) + else + environment = basic_environment(merge_global, efun()) + end + end + else + environment = basic_environment(merge_global) + end + + return environment +end + +local function read_template(template) + return ((template == "-" and io.stdin:read("*a")) or ltp.read_all(template)) +end + +local function render_template(template_data, start_lua, end_lua, environment) + local rfun = load_template(template_data, start_lua, end_lua) + local output = { } + execute_template(rfun, environment, output) + return table.concat(output) +end + +local function execute_env_code(env_code, environment) + for i = 1,#env_code do + local fun, emsg = loadstring(env_code[i]) + + if fun then + setfenv(fun, environment)() + else + error("error loading " .. env_code[i] .. "\n" .. emsg) + end + end +end + +local function render(outfile, num_passes, template, merge_global, + env_files, start_lua, end_lua, env_code) + local data = assert(read_template(template), "error reading " .. template) + local environment = load_environment(env_files, merge_global) + + execute_env_code(env_code, environment) + + if num_passes > 0 then + for i = 1,num_passes do + data = render_template(data, start_lua, end_lua, environment) + end + else + -- Prevent an infinite loop by capping expansion to 100 times. + num_passes = 1 + repeat + data = render_template(data, start_lua, end_lua, environment) + num_passes = num_passes + 1 + until data:find(start_lua, 1, true) == nil or num_passes >= 100 + end + + outfile:write(data); +end + +local function compile_as_function(outfile, template, start_lua, end_lua) + local data = read_template(template) + outfile:write(compile_template_as_function(data, start_lua, end_lua)) +end + +local function compile(outfile, template, start_lua, end_lua) + local data = read_template(template) + outfile:write(compile_template(data, start_lua, end_lua)) +end + +return ltp.merge_table( + { + compile_template_to_table = compile_template_to_table, + compile_template_as_function = compile_template_as_function, + compile_template = compile_template, + load_template = load_template, + execute_template = execute_template, + basic_environment = basic_environment, + load_environment = load_environment, + render_template = render_template, + execute_env_code = execute_env_code, + render = render, + compile_as_function = compile_as_function, + compile = compile + }, + ltp +)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ltp/util.lua Sun Sep 13 22:22:47 2009 +0300 @@ -0,0 +1,100 @@ +-- +-- Copyright 2007-2008 Savarese Software Research Corporation. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.savarese.com/software/ApacheLicense-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +local function slice(t, start, size) + local sz = (size or (#t - start + 1)) + local result = { } + + for i = 1, sz, 1 do + result[i] = t[start + i - 1] + end + + return result +end + +local function dual_index(index1, index2) + local index1_type = type(index1) + + if index1_type == "table" then + return function(t,k) + if index1[k] ~= nil then + return index1[k] + else + return index2[k] + end + end + elseif index1_type == "function" then + return function(t,k) + local v = index1(t,k) + if v ~= nil then + return v + else + return index2[k] + end + end + end +end + +local function merge_index(t1, t2) + local mt = getmetatable(t1) + + if mt ~= nil then + if mt.__index ~= nil then + mt.__index = dual_index(mt.__index, t2) + else + mt.__index = t2 + end + return t1 + else + return setmetatable(t1, {__index = t2}) + end +end + +local function merge_table(t1, t2) + local typet1 + + for k, v in pairs(t2) do + typet1 = type(t1[k]) + if t1[k] ~= v and type(v) == "table" then + if typet1 == "table" then + merge_table(t1[k], v) + elseif typet1 == "nil" then + t1[k] = v + end + end + end + + return merge_index(t1, t2) +end + +local function import(module_name, environment) + return setfenv(package.loaders[2](module_name), environment)() +end + +local function read_all(filename) + local file = io.open(filename, "r") + local data = ((file and file:read("*a")) or nil) + if file then + file:close() + end + return data +end + +return { slice = slice, + merge_index = merge_index, + merge_table = merge_table, + import = import, + read_all = read_all }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/luaext.lua Sun Sep 13 22:22:47 2009 +0300 @@ -0,0 +1,96 @@ +-- +-- ion/share/ioncore_luaext.lua +-- +-- Copyright (c) Tuomo Valkonen 2004-2009. +-- +-- See the included file LICENSE for details. +-- + + +--DOC +-- Make \var{str} shell-safe. +function string.shell_safe(str) + return "'"..string.gsub(str, "'", "'\\''").."'" +end + + +--DOC +-- Make copy of \var{table}. If \var{deep} is unset, shallow one-level +-- copy is made, otherwise a deep copy is made. +function table.copy(t, deep) + local function docopy(t, deep, seen) + local nt={} + for k, v in pairs(t) do + local v2=v + if deep and type(v)=="table" then + if seen[v] then + error(TR("Recursive table - unable to deepcopy")) + end + seen[v]=true + v2=docopy(v, deep, seen) + seen[v]=nil + end + nt[k]=v2 + end + return nt + end + return docopy(t, deep, deep and {}) +end + + +--DOC +-- Add entries that do not exist in \var{t1} from \var{t2} to \var{t1}. +function table.append(t1, t2) + for k, v in pairs(t2) do + if t1[k]==nil then + t1[k]=v + end + end + return t1 +end + + +--DOC +-- Create a table containing all entries from \var{t1} and those from +-- \var{t2} that are missing from \var{t1}. +function table.join(t1, t2) + return table.append(table.copy(t1, false), t2) +end + + +--DOC +-- Insert all positive integer entries from t2 into t1. +function table.icat(t1, t2) + for _, v in ipairs(t2) do + table.insert(t1, v) + end + return t1 +end + + +--DOC +-- Map all entries of \var{t} by \var{f}. +function table.map(f, t) + local res={} + for k, v in pairs(t) do + res[k]=f(v) + end + return res +end + + +--DOC +-- Export a list of functions from \var{lib} into global namespace. +function export(lib, ...) + for k, v in pairs({...}) do + _G[v]=lib[v] + end +end + +function io.openX(file, ...) + local f, err = io.open(file, ...) + if not f then + error(file..": "..err) + end + return f +end
--- a/path.lua Sat Sep 12 21:27:57 2009 +0300 +++ b/path.lua Sun Sep 13 22:22:47 2009 +0300 @@ -9,14 +9,18 @@ local sep=config.dirsep function join(p, f) - return p..sep..f + if p=="" then + return f + else + return p..sep..f + end end function dirbasename(p) local d, b = string.match(p, - "(.*)"..sep.."+([^"..sep.."]+)"..sep.."*$") + "^(.*)"..sep.."+([^"..sep.."]+)"..sep.."*$") if not b then - return string.match(p, "([^"..sep.."]*") + return "", p else return d, b end @@ -26,10 +30,23 @@ return tuple.fst(dirbasename(p)) end +function dirname_slash(p) + local dn=dirname(p) + if dn=="" then + return dn + else + return dn..sep + end +end + function basename(p) return tuple.snd(dirbasename(p)) end +function rmext(p) + return string.gsub(p, "%.[^.]*$", "") +end + -- would rather do this as an iterator, but can't -- coroutine.yield from gsub handler function split(p) @@ -40,11 +57,12 @@ table.insert(t, "/.") -- root p=p2 end - string.gsub(p, "([^"..sep.."]+)"..sep.."+", + string.gsub(p, "([^"..sep.."]+)", --..sep.."+", function(d) table.insert(t, d); end) return t end +--[[ function parts(p) local s={i=1, t=split(p)} local function g(s) @@ -55,8 +73,8 @@ return g, s end -function makepath(p) - local head="" +function makepath(p, head) + head=head or "" for d in parts(p) do head=head..d local a=lfs.attributes(head) @@ -71,13 +89,22 @@ head=head..sep end end +]] ---[[ -print(dirbasename("/foo/bar/baz")) - -for k in parts("//foo/bar/baz/quk") do - print(k) +function simplify(p) + local capts={} + local start=string.match(p, "^(/)") + string.gsub(p, "([^/]+)", + function(e) + if e==".." and #capts > 1 then + capts[#capts]=nil + elseif e~="." then + table.insert(capts, e) + end + end) + return (start or "")..table.concat(capts, "/") end -makepath("foo/bar/baz/quk") ---]] +function to_root(p) + return string.rep("../",#(split(p))-1) +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/breadcrumb.lua Sun Sep 13 22:22:47 2009 +0300 @@ -0,0 +1,8 @@ + +module("plugin.breadcrumb", package.seeall) + +require("path") + +function trail(env) + return "(TODO)" +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugin/inline.lua Sun Sep 13 22:22:47 2009 +0300 @@ -0,0 +1,80 @@ + +module("plugin.inline", package.seeall) + +require('handlers.render') + +function find(env, opts) + local found={} + for name, _ in pairs(env.pages) do + if string.match(name, opts.pattern) then + table.insert(found, name) + end + end + local function get_created(name) + local meta=env.pages[name].meta + return (meta and meta.created_at) + end + table.sort(found, function(a, b) + local ca=get_created(a) + local cb=get_created(b) + if not ca then + return false + elseif not cb then + return true + else + return ca > cb + end + end) + + if not opts.count then + return found + else + local results={} + for i=1,math.min(opts.count, #found) do + results[i]=found[i] + end + return results + end +end + +function render(env, opts, pages_) + local inlinepages={} + local page=env.page + local to_root=path.to_root(page.destination) + + for i, file in ipairs(pages_) do + local inlinepage=env.pages[file] + local relative_location, path_prefix + + if opts.absolute then + location=opts.absolute..inlinepage.destination + path_prefix=opts.absolute..path.dirname_slash(inlinepage.destination) + else + location=path.simplify(to_root..inlinepage.destination) + path_prefix=path.dirname_slash(location) + end + -- clean away index + if string.match(location, "^index%.[^.]*$") then + location="" + else + location=string.gsub(location, "/index%.[^.]*$", "/") + end + + inlinepages[i]=table.copy(inlinepage) + -- TODO: env väärin? + if not opts.no_content then + inlinepages[i].content=handlers.render.render(file, env, path_prefix) + end + inlinepages[i].location=location + end + + local tmplfile=path.join(env.paths.tmpl, opts.template or "inline.template") + local inline_template=filecache.get(tmplfile) + + local newenv=table.join(env, { inlinepages=inlinepages }) + return handlers.render.process_lua(inline_template, newenv) +end + +function inline(env, opts) + return render(env, opts, find(env, opts)) +end
--- a/scan.lua Sat Sep 12 21:27:57 2009 +0300 +++ b/scan.lua Sun Sep 13 22:22:47 2009 +0300 @@ -24,7 +24,7 @@ local a=lfs.attributes(n) if a.mode=='directory' then local nh=scan(n) - h[n]=nh + h[f]=nh elseif a.mode=='file' then h[f]=true end @@ -42,9 +42,13 @@ end end -function map(h, g) +function map(h, g, d) local function dir(prefix, name) - return path.join(prefix, name) + local p=path.join(prefix, name) + if d then + d(p) + end + return p end local function file(prefix, name)