summaryrefslogtreecommitdiffstats
path: root/acf/persistence/backends
diff options
context:
space:
mode:
Diffstat (limited to 'acf/persistence/backends')
-rw-r--r--acf/persistence/backends/augeas.lua26
-rw-r--r--acf/persistence/backends/files.lua68
-rw-r--r--acf/persistence/backends/json.lua110
3 files changed, 204 insertions, 0 deletions
diff --git a/acf/persistence/backends/augeas.lua b/acf/persistence/backends/augeas.lua
new file mode 100644
index 0000000..34d7df8
--- /dev/null
+++ b/acf/persistence/backends/augeas.lua
@@ -0,0 +1,26 @@
+--[[
+Copyright (c) 2012 Kaarle Ritvanen
+See LICENSE file for license details
+--]]
+
+module(..., package.seeall)
+
+local pth = require('acf.path')
+local map = require('acf.util').map
+
+backend = require('acf.object').class()
+
+function backend:init() self.aug = require('augeas').init() end
+
+function backend:get(path)
+ path = '/'..pth.join(unpack(path))
+ local _, count = self.aug:match(path)
+ if count == 0 then return end
+
+ local value = self.aug:get(path)
+ if value ~= nil then return value end
+
+ return map(pth.name, self.aug:match(path..'/*'))
+end
+
+-- TODO implement set function
diff --git a/acf/persistence/backends/files.lua b/acf/persistence/backends/files.lua
new file mode 100644
index 0000000..8e59ab9
--- /dev/null
+++ b/acf/persistence/backends/files.lua
@@ -0,0 +1,68 @@
+--[[
+Copyright (c) 2012 Kaarle Ritvanen
+See LICENSE file for license details
+--]]
+
+module(..., package.seeall)
+
+local pth = require('acf.path')
+local util = require('acf.persistence.util')
+
+require 'lfs'
+
+
+backend = require('acf.object').class()
+
+-- TODO cache expiration
+function backend:init() self.cache = {} end
+
+function backend:get(path)
+ local name = pth.join('/', unpack(path))
+
+ if not self.cache[name] then
+ local attrs = lfs.attributes(name)
+ if not attrs then return end
+
+ if attrs.mode == 'file' then
+ self.cache[name] = util.read_file(name)
+
+ elseif attrs.mode == 'directory' then
+ local res = {}
+ for fname in lfs.dir(name) do
+ if not ({['.']=true, ['..']=true})[fname] then
+ table.insert(res, fname)
+ end
+ end
+ return res
+
+ else error('Unsupported file type: '..name) end
+
+ -- TODO present symlinks as references
+ end
+
+ return self.cache[name]
+end
+
+function backend:set(mods)
+ for _, mod in pairs(mods) do
+ local path, t, value = unpack(mod)
+ local name = pth.join('/', unpack(path))
+
+ -- TODO save references (t == 'reference') as symlinks
+
+ if not t then
+ -- TODO del files & dirs
+ print('DEL', name)
+
+ elseif t == 'table' then
+ lfs.mkdir(name)
+
+ else
+ local file = util.open_file(name, 'w')
+ file:write(value)
+ file:close()
+
+ self.cache[name] = value
+ end
+ end
+end
diff --git a/acf/persistence/backends/json.lua b/acf/persistence/backends/json.lua
new file mode 100644
index 0000000..7300ce9
--- /dev/null
+++ b/acf/persistence/backends/json.lua
@@ -0,0 +1,110 @@
+--[[
+Copyright (c) 2012 Kaarle Ritvanen
+See LICENSE file for license details
+--]]
+
+module(..., package.seeall)
+
+local pth = require('acf.path')
+local util = require('acf.persistence.util')
+local copy = require('acf.util').copy
+
+require 'json'
+require 'lfs'
+
+
+local function keys(tbl)
+ local res = {}
+ for k, v in pairs(tbl) do table.insert(res, k) end
+ return res
+end
+
+
+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 attrs = lfs.attributes(fpath)
+ if not attrs or not ({directory=true, file=true})[attrs.mode] then
+ error('File or directory does not exist: '..fpath)
+ end
+
+ if attrs.mode == 'file' then return fpath, jpath end
+
+ assert(#jpath > 0)
+ end
+end
+
+function backend:_get(path)
+ local fpath, jpath = self:split_path(path)
+
+ if not self.cache[fpath] then
+ self.cache[fpath] = json.decode(util.read_file(fpath))
+ end
+
+ local res = self.cache[fpath]
+
+ while #jpath > 0 do
+ if res == nil then return end
+ assert(type(res) == 'table')
+ local next = jpath[1]
+ res = res[tonumber(next) or next]
+ table.remove(jpath, 1)
+ end
+
+ return res
+end
+
+function backend:get(path)
+ local res = self:_get(path)
+ return type(res) == 'table' and keys(res) or res
+end
+
+function backend:set(mods)
+ local dirty = {}
+
+ for _, mod in ipairs(mods) do
+ local p, t, value = unpack(mod)
+ local fpath, jpath = self:split_path(p)
+ if t == 'table' then value = {} end
+
+ if #jpath == 0 then self.cache[fpath] = value
+
+ else
+ local comps = copy(p)
+ local name = comps[#comps]
+ table.remove(comps)
+ self:_get(comps)[tonumber(name) or name] = value
+ end
+
+ dirty[fpath] = true
+ end
+
+ for path, _ in pairs(dirty) do
+ local file = util.open_file(path, 'w')
+ file:write(json.encode(self.cache[path]))
+ file:close()
+ end
+end