Improvements

Sun, 13 Sep 2009 22:22:47 +0300

author
Tuomo Valkonen <tuomov@iki.fi>
date
Sun, 13 Sep 2009 22:22:47 +0300
changeset 3
b2df1b3f2c83
parent 2
3975fa5ed630
child 4
4cb0d1dbc65b

Improvements

config.lua file | annotate | diff | comparison | revisions
dependency.lua file | annotate | diff | comparison | revisions
environment.lua file | annotate | diff | comparison | revisions
filecache.lua file | annotate | diff | comparison | revisions
handlers.lua file | annotate | diff | comparison | revisions
handlers/copy.lua file | annotate | diff | comparison | revisions
handlers/render.lua file | annotate | diff | comparison | revisions
lgen.lua file | annotate | diff | comparison | revisions
log.lua file | annotate | diff | comparison | revisions
ltp/LICENSE file | annotate | diff | comparison | revisions
ltp/README file | annotate | diff | comparison | revisions
ltp/template.lua file | annotate | diff | comparison | revisions
ltp/util.lua file | annotate | diff | comparison | revisions
luaext.lua file | annotate | diff | comparison | revisions
path.lua file | annotate | diff | comparison | revisions
plugin/breadcrumb.lua file | annotate | diff | comparison | revisions
plugin/inline.lua file | annotate | diff | comparison | revisions
scan.lua file | annotate | diff | comparison | revisions
time.lua file | annotate | diff | comparison | revisions
--- 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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/time.lua	Sun Sep 13 22:22:47 2009 +0300
@@ -0,0 +1,6 @@
+
+module("time", package.seeall)
+
+function now_iso()
+    return os.date("!%Y-%m-%dT%H:%M:%SZ")
+end

mercurial