This repository was archived by the owner on Nov 20, 2020. It is now read-only.
forked from lua-stdlib/lua-stdlib
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfstable.lua
More file actions
116 lines (107 loc) · 2.86 KB
/
fstable.lua
File metadata and controls
116 lines (107 loc) · 2.86 KB
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
108
109
110
111
112
113
114
115
116
--- Tables mapped to the filing system
-- Only string keys are permitted; package.dirsep characters are
-- converted to underscores.
-- Values are stored as strings (converted by tostring).
-- As with disk operations, a table's elements must be set to nil
-- (deleted) before the table itself can be set to nil.
module ("fstable", package.seeall)
require "io_ext"
require "table_ext"
require "io_ext"
require "lfs"
require "posix"
local function fsnext (dir)
local f
repeat
f = dir:next ()
until f ~= "." and f ~= ".."
return f
end
-- Metamethods for persistent tables
local metatable = {}
metatable.__index =
function (t, k)
local path = io.catfile (getmetatable (t).directory, k)
local attrs = lfs.attributes (path)
if attrs then
if attrs.mode == "file" then
return io.slurp (path)
elseif attrs.mode == "directory" then
return new (path)
end
end
return attrs
end
metatable.__newindex =
function (t, k, v)
local ty = type (v)
if ty == "thread" or ty == "function" or ty == "userdata" then
error ("cannot persist a " .. ty .. "")
elseif type (k) ~= "string" then
error ("keys of persistent tables must be of type string")
else
k = string.gsub (k, package.dirsep, "_")
local path = io.catfile (getmetatable (t).directory, k)
local vm = getmetatable (v)
if v == nil then
os.remove (path)
elseif type (v) ~= "table" then
local h = io.open (path, "w")
h:write (tostring (v))
h:close ()
elseif type (vm) == "table" and vm.metatable == metatable then
-- To match Lua semantics we'd hardlink, but that's not allowed for directories
local ok, errmsg = posix.link (vm.directory, path, true)
else
local ok, errmsg = lfs.mkdir (path)
if not ok then
error (errmsg)
end
new (path, v)
end
end
end
metatable.__pairs =
function (t)
local _, dir = lfs.dir (getmetatable (t).directory)
return function (dir)
local f = fsnext (dir)
if f then
return f, t[f]
end
end,
dir
end
metatable.__ipairs =
function (t)
local _, dir = lfs.dir (getmetatable (t).directory)
return function (dir, i)
local f = fsnext (dir)
if f then
return i + 1, f
end
end,
dir, 0
end
--- Bind a directory to a table
-- @param path directory path
-- @param t table to merge with directory
-- @return table bound to directory
function new (path, t)
if not path:find ("^" .. package.dirsep) then
path = io.catfile (lfs.currentdir (), path)
end
if lfs.attributes (path, "mode") ~= "directory" then
error ("`" .. path .. "' does not exist or is not a directory")
end
local m = table.clone (metatable)
m.directory = path
m.metatable = metatable
local d = setmetatable ({}, m)
if t then
for i, v in pairs (t) do
d[i] = v
end
end
return d
end