1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
--[[
Copyright (c) 2012-2014 Kaarle Ritvanen
See LICENSE file for license details
--]]
local topology = require('aconf.model.root').topology
local pth = require('aconf.path')
local util = require('aconf.persistence.util')
local copy = require('aconf.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('aconf.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(util.tostring(value))
file:close()
self.cache[name] = value
end
end
end
end
return backend
|