From 5d663a122ea39802c096a57ad3fb471dee347759 Mon Sep 17 00:00:00 2001 From: Kaarle Ritvanen Date: Wed, 20 Mar 2013 14:11:41 +0200 Subject: allow escaped slashes in object path names --- acf/init.lua | 2 +- acf/loader.lua | 22 ++++++++++++++++ acf/model/init.lua | 4 +-- acf/path.lua | 52 ++++++++++++++++++++++++++----------- acf/persistence/backends/augeas.lua | 4 +-- acf/persistence/backends/files.lua | 6 ++--- acf/persistence/backends/json.lua | 6 ++--- acf/persistence/init.lua | 7 +++-- acf/util.lua | 16 ------------ 9 files changed, 75 insertions(+), 44 deletions(-) create mode 100644 acf/loader.lua (limited to 'acf') diff --git a/acf/init.lua b/acf/init.lua index 8f89c08..b20d1a1 100644 --- a/acf/init.lua +++ b/acf/init.lua @@ -5,7 +5,7 @@ See LICENSE file for license details module(..., package.seeall) -require('acf.util').loadmods('modules') +require('acf.loader').loadmods('modules') require 'acf.model' call = require('acf.error').call diff --git a/acf/loader.lua b/acf/loader.lua new file mode 100644 index 0000000..d66403a --- /dev/null +++ b/acf/loader.lua @@ -0,0 +1,22 @@ +--[[ +Copyright (c) 2012-2013 Kaarle Ritvanen +See LICENSE file for license details +--]] + +module(..., package.seeall) + +local pth = require('acf.path') +require 'lfs' +require 'stringy' + +function loadmods(subdir) + local comps = pth.split('acf/'..subdir) + local res = {} + for modfile in lfs.dir(pth.mjoin(unpack(comps))) do + if stringy.endswith(modfile, '.lua') then + local name = string.sub(modfile, 1, -5) + res[name] = require(table.concat(comps, '.')..'.'..name) + end + end + return res +end diff --git a/acf/model/init.lua b/acf/model/init.lua index 6b1fd64..bf4f7b4 100644 --- a/acf/model/init.lua +++ b/acf/model/init.lua @@ -136,7 +136,7 @@ function Reference:meta(context) end function Reference:follow(context, value) - return context.txn:search(pth.join(self:abs_scope(context), value)) + return context.txn:search(pth.mjoin(self:abs_scope(context), value)) end function Reference:load(context) @@ -163,7 +163,7 @@ function Reference:_validate(context, value) end -- assume one-level ref for now - if string.find(value, '/') then + if #pth.split(value) > 1 then raise(path, 'Subtree references not yet supported') end diff --git a/acf/path.lua b/acf/path.lua index 15d3fca..f18d701 100644 --- a/acf/path.lua +++ b/acf/path.lua @@ -5,13 +5,7 @@ See LICENSE file for license details module(..., package.seeall) -require 'stringy' - -local function filter(func, tbl) - local res = {} - for _, v in ipairs(tbl) do if func(v) then table.insert(res, v) end end - return res -end +local map = require('acf.util').map function is_absolute(path) @@ -35,24 +29,52 @@ function to_absolute(path, base) return '/'..table.concat(comps, '/') end -function join(p1, p2, ...) + +local function escape(comp) + local res = string.gsub(comp, '([\\/])', '\\%1') + return res +end + + +function join(parent, name) return mjoin(parent, escape(name)) end + +function mjoin(p1, p2, ...) if not p2 then return p1 end if not is_absolute(p2) then p2 = '/'..p2 end - return join((p1 == '/' and '' or p1)..p2, unpack(arg)) + return mjoin((p1 == '/' and '' or p1)..p2, unpack(arg)) end + function split(path) - -- assume absolute paths - assert(is_absolute(path)) - if path == '/' then return {} end - return filter(function(s) return s > '' end, - stringy.split(string.sub(path, 2, -1), '/')) + local res = {} + local comp = '' + + local function merge(s) if s > '' then table.insert(res, s) end end + + while true do + local prefix, sep, suffix = string.match(path, '([^\\/]*)([\\/])(.*)') + if not prefix then + merge(comp..path) + return res + end + + comp = comp..prefix + if sep == '\\' then + comp = comp..string.sub(suffix, 1, 1) + path = string.sub(suffix, 2, -1) + else + merge(comp) + comp = '' + path = suffix + end + end end + function parent(path) local comps = split(path) table.remove(comps) - return join('/', unpack(comps)) + return mjoin('/', unpack(map(escape, comps))) end function name(path) diff --git a/acf/persistence/backends/augeas.lua b/acf/persistence/backends/augeas.lua index 34d7df8..cf4614f 100644 --- a/acf/persistence/backends/augeas.lua +++ b/acf/persistence/backends/augeas.lua @@ -1,5 +1,5 @@ --[[ -Copyright (c) 2012 Kaarle Ritvanen +Copyright (c) 2012-2013 Kaarle Ritvanen See LICENSE file for license details --]] @@ -13,7 +13,7 @@ backend = require('acf.object').class() function backend:init() self.aug = require('augeas').init() end function backend:get(path) - path = '/'..pth.join(unpack(path)) + path = '/'..pth.mjoin(unpack(path)) local _, count = self.aug:match(path) if count == 0 then return end diff --git a/acf/persistence/backends/files.lua b/acf/persistence/backends/files.lua index 8e59ab9..bc9c111 100644 --- a/acf/persistence/backends/files.lua +++ b/acf/persistence/backends/files.lua @@ -1,5 +1,5 @@ --[[ -Copyright (c) 2012 Kaarle Ritvanen +Copyright (c) 2012-2013 Kaarle Ritvanen See LICENSE file for license details --]] @@ -17,7 +17,7 @@ backend = require('acf.object').class() function backend:init() self.cache = {} end function backend:get(path) - local name = pth.join('/', unpack(path)) + local name = pth.mjoin('/', unpack(path)) if not self.cache[name] then local attrs = lfs.attributes(name) @@ -46,7 +46,7 @@ end function backend:set(mods) for _, mod in pairs(mods) do local path, t, value = unpack(mod) - local name = pth.join('/', unpack(path)) + local name = pth.mjoin('/', unpack(path)) -- TODO save references (t == 'reference') as symlinks diff --git a/acf/persistence/backends/json.lua b/acf/persistence/backends/json.lua index 7300ce9..6500d13 100644 --- a/acf/persistence/backends/json.lua +++ b/acf/persistence/backends/json.lua @@ -1,5 +1,5 @@ --[[ -Copyright (c) 2012 Kaarle Ritvanen +Copyright (c) 2012-2013 Kaarle Ritvanen See LICENSE file for license details --]] @@ -34,7 +34,7 @@ function backend:split_path(path) local res while #fpath > 0 do - local fp = pth.join('/', unpack(fpath)) + local fp = pth.mjoin('/', unpack(fpath)) if self.cache[fp] then return fp, jpath end table.insert(jpath, 1, fpath[#fpath]) table.remove(fpath) @@ -43,7 +43,7 @@ function backend:split_path(path) fpath = '/' while true do - fpath = pth.join(fpath, jpath[1]) + fpath = pth.mjoin(fpath, jpath[1]) table.remove(jpath, 1) local attrs = lfs.attributes(fpath) diff --git a/acf/persistence/init.lua b/acf/persistence/init.lua index 2533560..479620b 100644 --- a/acf/persistence/init.lua +++ b/acf/persistence/init.lua @@ -5,6 +5,7 @@ See LICENSE file for license details module(..., package.seeall) +local loadmods = require('acf.loader').loadmods local object = require('acf.object') local super = object.super local pth = require('acf.path') @@ -15,8 +16,10 @@ DataStore = object.class(require('acf.transaction.backend').TransactionBackend) function DataStore:init() super(self, DataStore):init() - self.backends = util.map(function(m) return m.backend() end, - util.loadmods('persistence/backends')) + self.backends = util.map( + function(m) return m.backend() end, + loadmods('persistence/backends') + ) end function DataStore:split_path(path) diff --git a/acf/util.lua b/acf/util.lua index 9ca287c..8dd54cc 100644 --- a/acf/util.lua +++ b/acf/util.lua @@ -28,19 +28,3 @@ function map(func, tbl) for k, v in pairs(tbl) do res[k] = func(copy(v)) end return res end - - -local pth = require('acf.path') -require 'lfs' - -function loadmods(subdir) - local comps = pth.split('/acf/'..subdir) - local res = {} - for modfile in lfs.dir(pth.join(unpack(comps))) do - if stringy.endswith(modfile, '.lua') then - local name = string.sub(modfile, 1, -5) - res[name] = require(table.concat(comps, '.')..'.'..name) - end - end - return res -end -- cgit v1.2.3