diff options
Diffstat (limited to 'acf/persistence')
-rw-r--r-- | acf/persistence/backends/augeas.lua | 153 | ||||
-rw-r--r-- | acf/persistence/backends/files.lua | 107 | ||||
-rw-r--r-- | acf/persistence/backends/json.lua | 79 | ||||
-rw-r--r-- | acf/persistence/backends/null.lua | 10 | ||||
-rw-r--r-- | acf/persistence/backends/volatile.lua | 46 | ||||
-rw-r--r-- | acf/persistence/init.lua | 79 | ||||
-rw-r--r-- | acf/persistence/util.lua | 22 |
7 files changed, 0 insertions, 496 deletions
diff --git a/acf/persistence/backends/augeas.lua b/acf/persistence/backends/augeas.lua deleted file mode 100644 index 4cf623a..0000000 --- a/acf/persistence/backends/augeas.lua +++ /dev/null @@ -1,153 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Kaarle Ritvanen -See LICENSE file for license details ---]] - -local topology = require('acf.model.root').topology -local pth = require('acf.path') - -local util = require('acf.util') -local copy = util.copy - - -local function aug_path(path) return pth.join('/files', unpack(path)) end - -local function strip_name(name) - return type(name) == 'string' and name:match('^[^][/=)%s]+') or name -end - -local function ipath(path, index) return path..'['..index..']' end - - -local backend = require('acf.object').class() - -function backend:init() self.aug = require('augeas').init() end - -function backend:find(path, leaf) - util.map( - function(comp) - assert( - comp == strip_name(comp) and ( - type(comp) == 'number' or not comp:match('^%.+$') - ) - ) - end, - path - ) - local res = aug_path(path) - - if #self.aug:match(res) == 0 and #path > 1 and leaf then - local index = path[#path] - if type(index) == 'number' then - local ppath = copy(path) - table.remove(ppath) - ppath = aug_path(ppath) - - if #self.aug:match(ppath) > 0 and #self.aug:match( - ppath..'/*' - ) == 0 then - return ipath(ppath, index), ppath, index - end - end - end - - return res -end - -function backend:get(path, top) - local tpe = top and top.type - local leaf = tpe and tpe ~= 'table' - local apath, mvpath = self:find(path, leaf or not tpe) - - local matches = self.aug:match(apath) - if mvpath then - assert(#matches < 2) - leaf = true - end - - if #matches == 0 then return end - - if #matches > 1 then - assert(not leaf) - local res = {} - path = copy(path) - for i, _ in ipairs(matches) do - table.insert(path, i) - if self:get(path) then table.insert(res, i) end - table.remove(path) - end - return res - end - - local value = self.aug:get(matches[1]) - if value then return tpe == 'table' and {1} or value end - if leaf then return end - - local names = {} - for _, child in ipairs(self.aug:match(apath..'/*')) do - names[strip_name(pth.name(child))] = true - end - return util.keys(names) -end - -function backend:set(mods) - local gcpaths = {} - - for _, mod in ipairs(mods) do - local path, value = unpack(mod) - - local delete = value == nil - self.aug:rm(aug_path(path)..(delete and '' or '/*')) - - local apath, mvpath, index = self:find(path, type(value) ~= 'table') - local mpath = mvpath or apath - - if not delete then - if #self.aug:match(mpath) == 0 then - - local function order(path) - return topology('/augeas'..path).order - end - local ord = order(pth.join('/', unpack(path))) - - for _, sibling in ipairs(self.aug:match(pth.parent(mpath)..'/*')) do - if order(strip_name(sibling):sub(7, -1)) > ord then - self.aug:insert(sibling, pth.name(mpath), true) - break - end - end - end - - if mvpath then - local size = #self.aug:match(mvpath) - while size < index do - self.aug:insert(ipath(mvpath, size), pth.name(mvpath)) - size = size + 1 - end - end - end - - if type(value) == 'table' then value = nil end - if not delete or mvpath then self.aug:set(apath, value) - elseif apath > '/' then apath = pth.parent(apath) end - - if delete or value == '' then gcpaths[mpath] = true end - end - - local function gc(path) - if path == '/' or #self.aug:match(path..'/*') > 0 then return end - if self.aug:rm(path.."[. = '']") > 0 then gc(pth.parent(path)) end - end - for p, _ in pairs(gcpaths) do gc(p) end - - if self.aug:save() ~= 0 then - print('Augeas save failed') - for _, ep in ipairs(self.aug:match('/augeas//error')) do - print(ep, self.aug:get(ep)) - end - assert(false) - end -end - - -return backend diff --git a/acf/persistence/backends/files.lua b/acf/persistence/backends/files.lua deleted file mode 100644 index 7d03e12..0000000 --- a/acf/persistence/backends/files.lua +++ /dev/null @@ -1,107 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Kaarle Ritvanen -See LICENSE file for license details ---]] - -local topology = require('acf.model.root').topology -local pth = require('acf.path') -local util = require('acf.persistence.util') -local copy = require('acf.util').copy - -local posix = require('posix') -local stringy = require('stringy') - - -local function get_scope(top) - if not top or top.type ~= 'reference' or not pth.is_unique(top.scope) then - return - end - - return stringy.startswith( - top.scope, '/files/' - ) and top.scope:sub(7, -1) or nil -end - - -local backend = require('acf.object').class() - --- TODO cache expiration -function backend:init() self.cache = {} end - -function backend:get(path, top) - local name = pth.join('/', unpack(path)) - - if not self.cache[name] then - local t = posix.stat(name, 'type') - if not t then return end - - if t == 'regular' then - self.cache[name] = util.read_file(name) - - elseif t == 'link' then - -- TODO handle relative symlinks - local target = posix.readlink(name) - assert(target) - - local scope = get_scope(top) - assert(scope) - scope = scope..'/' - - local slen = scope:len() - assert(target:sub(1, slen) == scope) - return target:sub(slen + 1, -1) - - elseif t == 'directory' then - local res = {} - for _, fname in ipairs(posix.dir(name)) do - if not ({['.']=true, ['..']=true})[fname] then - table.insert(res, pth.name(fname)) - end - end - return res - - else error('Unsupported file type: '..name) end - end - - return self.cache[name] -end - -function backend:set(mods) - for _, mod in pairs(mods) do - local path, value = unpack(mod) - local name = pth.join('/', unpack(path)) - - if value == nil then - print('DEL', name) - - local t = posix.stat(name, 'type') - if t == 'directory' then - assert(posix.rmdir(name)) - elseif t then assert(os.remove(name)) end - - self.cache[name] = nil - - elseif type(value) == 'table' then - assert(posix.mkdir(name)) - - else - local scope = get_scope(topology('/files'..name)) - - if scope then - -- TODO use relative symlink - os.remove(name) - assert(posix.link(pth.to_absolute(value, scope), name, true)) - - else - local file = util.open_file(name, 'w') - file:write(tostring(value)) - file:close() - - self.cache[name] = value - end - end - end -end - - -return backend diff --git a/acf/persistence/backends/json.lua b/acf/persistence/backends/json.lua deleted file mode 100644 index e0cd66e..0000000 --- a/acf/persistence/backends/json.lua +++ /dev/null @@ -1,79 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Kaarle Ritvanen -See LICENSE file for license details ---]] - -local pth = require('acf.path') -local Cache = require('acf.persistence.backends.volatile') -local util = require('acf.persistence.util') -local copy = require('acf.util').copy - -local json = require('cjson') -local posix = require('posix') - - -local backend = require('acf.object').class() - -function backend:init() - -- TODO cache expiration - self.cache = {} - self.dirty = {} -end - -function backend:split_path(path) - local fpath = copy(path) - local jpath = {} - local res - - while #fpath > 0 do - local fp = pth.join('/', unpack(fpath)) - if self.cache[fp] then return fp, jpath end - table.insert(jpath, 1, fpath[#fpath]) - table.remove(fpath) - end - - fpath = '/' - - while true do - fpath = pth.join(fpath, jpath[1]) - table.remove(jpath, 1) - - local t = posix.stat(fpath, 'type') - if t == 'link' then t = posix.stat(posix.readlink(fpath), 'type') end - if not t or not ({directory=true, regular=true})[t] then - error('File or directory does not exist: '..fpath) - end - - if t == 'regular' then return fpath, jpath end - - assert(#jpath > 0) - end -end - -function backend:get(path, top) - local fpath, jpath = self:split_path(path) - if not self.cache[fpath] then - self.cache[fpath] = Cache(json.decode(util.read_file(fpath))) - end - return self.cache[fpath]:get(jpath, top) -end - -function backend:set(mods) - local dirty = {} - - for _, mod in ipairs(mods) do - local path, value = unpack(mod) - local fpath, jpath = self:split_path(path) - self.cache[fpath]:_set(jpath, value) - dirty[fpath] = true - end - - for path, _ in pairs(dirty) do - local file = util.open_file(path, 'w') - file:write(json.encode(self.cache[path]:_get{})) - file:close() - end -end - - -return backend diff --git a/acf/persistence/backends/null.lua b/acf/persistence/backends/null.lua deleted file mode 100644 index 7ff58ce..0000000 --- a/acf/persistence/backends/null.lua +++ /dev/null @@ -1,10 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Kaarle Ritvanen -See LICENSE file for license details ---]] - -local backend = require('acf.object').class() -function backend:get(path, top) if #path == 0 then return {} end end -function backend:set(mods) end - -return backend diff --git a/acf/persistence/backends/volatile.lua b/acf/persistence/backends/volatile.lua deleted file mode 100644 index a83f7e3..0000000 --- a/acf/persistence/backends/volatile.lua +++ /dev/null @@ -1,46 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Kaarle Ritvanen -See LICENSE file for license details ---]] - -local util = require('acf.util') - - -local backend = require('acf.object').class() - -function backend:init(data) self.data = data or {} end - -function backend:_get(path) - local res = self.data - for _, comp in ipairs(path) do - if res == nil then return end - assert(type(res) == 'table') - res = res[comp] - end - return res -end - -function backend:get(path, top) - local res = self:_get(path) - return type(res) == 'table' and util.keys(res) or res -end - -function backend:_set(path, value) - if type(value) == 'table' then value = {} end - - if #path == 0 then self.data = value - - else - local comps = util.copy(path) - local name = comps[#comps] - table.remove(comps) - self:_get(comps)[name] = value - end -end - -function backend:set(mods) - for _, mod in ipairs(mods) do self:_set(unpack(mod)) end -end - - -return backend diff --git a/acf/persistence/init.lua b/acf/persistence/init.lua deleted file mode 100644 index 044d4b2..0000000 --- a/acf/persistence/init.lua +++ /dev/null @@ -1,79 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Kaarle Ritvanen -See LICENSE file for license details ---]] - -local M = {} - -local loadmods = require('acf.loader') -local topology = require('acf.model.root').topology -local object = require('acf.object') -local pth = require('acf.path') -local util = require('acf.util') - -local stringy = require('stringy') - - -local DataStore = object.class( - require('acf.transaction.backend').TransactionBackend -) - -function DataStore:init() - object.super(self, DataStore):init() - self.backends = util.map( - function(m) return m() end, - loadmods('persistence/backends') - ) -end - -function DataStore:split_path(path) - local comps = pth.split(path) - local backend = self.backends[comps[1]] - assert(backend) - table.remove(comps, 1) - return backend, comps -end - -function DataStore:get(path) - local backend, comps = self:split_path(path) - local top = topology(path) - - local res = backend:get(comps, top) - - if top then - local t = top.type - if t and res ~= nil then - local atype = type(res) - - if t == 'table' then assert(atype == 'table') - - else - assert(atype ~= 'table') - - if t == 'string' then res = tostring(res) - elseif t == 'number' then res = tonumber(res) - elseif t == 'boolean' then - res = (res and res ~= 'false') and true or false - elseif t == 'reference' then assert(atype == 'string') - else assert(false) end - end - end - end - - return util.copy(res), self.mod_time[path] or 0 -end - -function DataStore:_set_multiple(mods) - local bms = {} - - for _, mod in ipairs(mods) do - local path, value = unpack(mod) - local backend, comps = self:split_path(path) - table.insert(util.setdefault(bms, backend, {}), {comps, value}) - end - - for backend, bm in pairs(bms) do backend:set(bm) end -end - - -return DataStore() diff --git a/acf/persistence/util.lua b/acf/persistence/util.lua deleted file mode 100644 index a657411..0000000 --- a/acf/persistence/util.lua +++ /dev/null @@ -1,22 +0,0 @@ ---[[ -Copyright (c) 2012-2013 Kaarle Ritvanen -See LICENSE file for license details ---]] - -local M = {} - -function M.open_file(path, mode) - local file = io.open(path, mode) - if not file then error('Cannot open file: '..path) end - return file -end - -function M.read_file(path) - local file = M.open_file(path) - local data = '' - for line in file:lines() do data = data..line end - file:close() - return data -end - -return M |