summaryrefslogtreecommitdiffstats
path: root/acf/persistence
diff options
context:
space:
mode:
Diffstat (limited to 'acf/persistence')
-rw-r--r--acf/persistence/backends/augeas.lua153
-rw-r--r--acf/persistence/backends/files.lua107
-rw-r--r--acf/persistence/backends/json.lua79
-rw-r--r--acf/persistence/backends/null.lua10
-rw-r--r--acf/persistence/backends/volatile.lua46
-rw-r--r--acf/persistence/init.lua79
-rw-r--r--acf/persistence/util.lua22
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