rename LFS to FS store
s-ol
3 years ago
15 | 15 | RUN tup init && tup generate --config tup.docker.config build-static.sh && ./build-static.sh |
16 | 16 | |
17 | 17 | EXPOSE 8000 |
18 | ENTRYPOINT ["moon", "build/server.moon", "/db.sqlite3", "0.0.0.0", "8000"] | |
18 | ENTRYPOINT ["moon", "build/server.moon", "sql:/db.sqlite3", "0.0.0.0", "8000"] |
0 | lfs = require 'lfs' | |
1 | ||
2 | -- split filename into dirname + basename | |
3 | dir_base = (path) -> | |
4 | dir, base = path\match '(.-)([^/]-)$' | |
5 | if dir and #dir > 0 | |
6 | dir = dir\sub 1, #dir - 1 | |
7 | ||
8 | dir, base | |
9 | ||
10 | class FSStore | |
11 | new: (opts = {}) => | |
12 | opts.root or= 'root' | |
13 | opts.verbose or= false | |
14 | ||
15 | if not opts.verbose | |
16 | @log = -> | |
17 | ||
18 | -- ensure path doesnt end with a slash | |
19 | @root = opts.root\match '^(.-)/?$' | |
20 | @log "opening '#{opts.root}'..." | |
21 | ||
22 | log: (...) => | |
23 | print "[DB]", ... | |
24 | ||
25 | -- fileders | |
26 | list_fileders_in: (path='') => | |
27 | coroutine.wrap -> | |
28 | for entry_name in lfs.dir @root .. path | |
29 | continue if '.' == entry_name\sub 1, 1 | |
30 | entry_path = @root .. "#{path}/#{entry_name}" | |
31 | if 'directory' == lfs.attributes entry_path, 'mode' | |
32 | coroutine.yield "#{path}/#{entry_name}" | |
33 | ||
34 | list_all_fileders: (path='') => | |
35 | coroutine.wrap -> | |
36 | for path in @list_fileders_in path | |
37 | coroutine.yield path | |
38 | for p in @list_all_fileders path | |
39 | coroutine.yield p | |
40 | ||
41 | create_fileder: (parent, name) => | |
42 | @log "creating fileder #{path}" | |
43 | path = "#{parent}/#{name}" | |
44 | assert lfs.mkdir @root .. path | |
45 | path | |
46 | ||
47 | remove_fileder: (path) => | |
48 | @log "removing fileder #{path}" | |
49 | ||
50 | rmdir = (path) -> | |
51 | for file in lfs.dir path | |
52 | continue if '.' == file\sub 1, 1 | |
53 | ||
54 | file_path = "#{path}/#{file}" | |
55 | switch lfs.attributes file_path, 'mode' | |
56 | when 'file' | |
57 | assert os.remove file_path | |
58 | when 'directory' | |
59 | assert rmdir file_path | |
60 | ||
61 | lfs.rmdir path | |
62 | ||
63 | rmdir @root .. path | |
64 | ||
65 | rename_fileder: (path, next_name) => | |
66 | @log "renaming fileder #{path} -> '#{next_name}'" | |
67 | parent, name = dir_base path | |
68 | assert os.rename path, @root .. "#{parent}/#{next_name}" | |
69 | ||
70 | move_fileder: (path, next_parent) => | |
71 | @log "moving fileder #{path} -> #{next_parent}/" | |
72 | parent, name = dir_base path | |
73 | assert os.rename @root .. path, @root .. "#{next_parent}/#{name}" | |
74 | ||
75 | -- facets | |
76 | list_facets: (path) => | |
77 | coroutine.wrap -> | |
78 | for entry_name in lfs.dir @root .. path | |
79 | entry_path = "#{@root .. path}/#{entry_name}" | |
80 | if 'file' == lfs.attributes entry_path, 'mode' | |
81 | entry_name = (entry_name\match '(.*)%.%w+') or entry_name | |
82 | entry_name = entry_name\gsub '%$', '/' | |
83 | name, type = entry_name\match '(%w+): *(.+)' | |
84 | if not name | |
85 | name = '' | |
86 | type = entry_name | |
87 | ||
88 | coroutine.yield name, type | |
89 | ||
90 | tofp: (path, name, type) => | |
91 | type = "#{name}: #{type}" if #name > 0 | |
92 | type = type\gsub '%/', '$' | |
93 | @root .. "#{path}/#{type}" | |
94 | ||
95 | locate: (path, name, type) => | |
96 | return unless lfs.attributes @root .. path, 'mode' | |
97 | ||
98 | type = type\gsub '%/', '$' | |
99 | name = "#{name}: " if #name > 0 | |
100 | name = name .. type | |
101 | name = name\gsub '([^%w])', '%%%1' | |
102 | ||
103 | local file_name | |
104 | for entry_name in lfs.dir @root .. path | |
105 | if (entry_name\match "^#{name}$") or entry_name\match "^#{name}%.%w+$" | |
106 | if file_name | |
107 | error "two files match #{name}: #{file_name} and #{entry_name}!" | |
108 | file_name = entry_name | |
109 | ||
110 | ||
111 | file_name and @root .. "#{path}/#{file_name}" | |
112 | ||
113 | load_facet: (path, name, type) => | |
114 | filepath = @locate path, name, type | |
115 | return unless filepath | |
116 | file = assert (io.open filepath, 'rb'), "couldn't open facet file '#{filepath}'" | |
117 | with file\read '*all' | |
118 | file\close! | |
119 | ||
120 | create_facet: (path, name, type, blob) => | |
121 | @log "creating facet #{path} | #{name}: #{type}" | |
122 | assert blob, "cant create facet without value!" | |
123 | ||
124 | filepath = @tofp path, name, type | |
125 | if lfs.attributes filepath, 'mode' | |
126 | error "facet file already exists!" | |
127 | ||
128 | file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'" | |
129 | file\write blob | |
130 | file\close! | |
131 | ||
132 | remove_facet: (path, name, type) => | |
133 | @log "removing facet #{path} | #{name}: #{type}" | |
134 | ||
135 | filepath = @locate path, name, type | |
136 | assert filepath, "couldn't locate facet!" | |
137 | assert os.remove filepath | |
138 | ||
139 | rename_facet: (path, name, type, next_name) => | |
140 | @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}" | |
141 | filepath = @locate path, name, type | |
142 | assert filepath, "couldn't locate facet!" | |
143 | assert os.rename filepath, @tofp path, next_name, type | |
144 | ||
145 | update_facet: (path, name, type, blob) => | |
146 | @log "updating facet #{path} | #{name}: #{type}" | |
147 | filepath = @locate path, name, type | |
148 | assert filepath, "couldn't locate facet!" | |
149 | file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'" | |
150 | file\write blob | |
151 | file\close! | |
152 | ||
153 | { | |
154 | :FSStore | |
155 | } |
0 | 0 | require = relative ..., 0 |
1 | 1 | |
2 | 2 | -- instantiate a store from a CLI arg |
3 | -- e.g.: sql, lfs:/path/to/root, sql:MEMORY, sql:db.sqlite3 | |
3 | -- e.g.: sql, fs:/path/to/root, sql:MEMORY, sql:db.sqlite3 | |
4 | 4 | get_store = (args='sql', opts={verbose: true}) -> |
5 | 5 | type, arg = args\match '(%w+):(.*)' |
6 | 6 | type = arg unless type |
12 | 12 | if arg == 'MEMORY' |
13 | 13 | opts.memory = true |
14 | 14 | else |
15 | opts.name = arg | |
15 | opts.file = arg | |
16 | 16 | |
17 | 17 | SQLStore opts |
18 | 18 | |
19 | when 'lfs' | |
20 | import LFSStore from require '.lfs' | |
19 | when 'fs' | |
20 | import LFSStore from require '.fs' | |
21 | 21 | |
22 | 22 | opts.root = arg |
23 | 23 | |
24 | 24 | LFSStore opts |
25 | 25 | |
26 | 26 | else |
27 | warn "unknown or missing value for STORE: valid types values are sql, lfs" | |
27 | warn "unknown or missing value for STORE: valid types values are sql, fs" | |
28 | 28 | os.exit 1 |
29 | 29 | |
30 | 30 | { |
0 | lfs = require 'lfs' | |
1 | ||
2 | -- split filename into dirname + basename | |
3 | dir_base = (path) -> | |
4 | dir, base = path\match '(.-)([^/]-)$' | |
5 | if dir and #dir > 0 | |
6 | dir = dir\sub 1, #dir - 1 | |
7 | ||
8 | dir, base | |
9 | ||
10 | ||
11 | class LFSStore | |
12 | new: (opts = {}) => | |
13 | opts.root or= 'root' | |
14 | opts.verbose or= false | |
15 | ||
16 | if not opts.verbose | |
17 | @log = -> | |
18 | ||
19 | -- ensure path doesnt end with a slash | |
20 | @root = opts.root\match '^(.-)/?$' | |
21 | @log "opening '#{opts.root}'..." | |
22 | ||
23 | log: (...) => | |
24 | print "[DB]", ... | |
25 | ||
26 | -- fileders | |
27 | list_fileders_in: (path='') => | |
28 | coroutine.wrap -> | |
29 | for entry_name in lfs.dir @root .. path | |
30 | continue if '.' == entry_name\sub 1, 1 | |
31 | entry_path = @root .. "#{path}/#{entry_name}" | |
32 | if 'directory' == lfs.attributes entry_path, 'mode' | |
33 | coroutine.yield "#{path}/#{entry_name}" | |
34 | ||
35 | list_all_fileders: (path='') => | |
36 | coroutine.wrap -> | |
37 | for path in @list_fileders_in path | |
38 | coroutine.yield path | |
39 | for p in @list_all_fileders path | |
40 | coroutine.yield p | |
41 | ||
42 | create_fileder: (parent, name) => | |
43 | @log "creating fileder #{path}" | |
44 | path = "#{parent}/#{name}" | |
45 | assert lfs.mkdir @root .. path | |
46 | path | |
47 | ||
48 | remove_fileder: (path) => | |
49 | @log "removing fileder #{path}" | |
50 | ||
51 | rmdir = (path) -> | |
52 | for file in lfs.dir path | |
53 | continue if '.' == file\sub 1, 1 | |
54 | ||
55 | file_path = "#{path}/#{file}" | |
56 | switch lfs.attributes file_path, 'mode' | |
57 | when 'file' | |
58 | assert os.remove file_path | |
59 | when 'directory' | |
60 | assert rmdir file_path | |
61 | ||
62 | lfs.rmdir path | |
63 | ||
64 | rmdir @root .. path | |
65 | ||
66 | rename_fileder: (path, next_name) => | |
67 | @log "renaming fileder #{path} -> '#{next_name}'" | |
68 | parent, name = dir_base path | |
69 | assert os.rename path, @root .. "#{parent}/#{next_name}" | |
70 | ||
71 | move_fileder: (path, next_parent) => | |
72 | @log "moving fileder #{path} -> #{next_parent}/" | |
73 | parent, name = dir_base path | |
74 | assert os.rename @root .. path, @root .. "#{next_parent}/#{name}" | |
75 | ||
76 | -- facets | |
77 | list_facets: (path) => | |
78 | coroutine.wrap -> | |
79 | for entry_name in lfs.dir @root .. path | |
80 | entry_path = "#{@root .. path}/#{entry_name}" | |
81 | if 'file' == lfs.attributes entry_path, 'mode' | |
82 | entry_name = (entry_name\match '(.*)%.%w+') or entry_name | |
83 | entry_name = entry_name\gsub '%$', '/' | |
84 | name, type = entry_name\match '(%w+): *(.+)' | |
85 | if not name | |
86 | name = '' | |
87 | type = entry_name | |
88 | ||
89 | coroutine.yield name, type | |
90 | ||
91 | tofp: (path, name, type) => | |
92 | type = "#{name}: #{type}" if #name > 0 | |
93 | type = type\gsub '%/', '$' | |
94 | @root .. "#{path}/#{type}" | |
95 | ||
96 | locate: (path, name, type) => | |
97 | return unless lfs.attributes @root .. path, 'mode' | |
98 | ||
99 | type = type\gsub '%/', '$' | |
100 | name = "#{name}: " if #name > 0 | |
101 | name = name .. type | |
102 | name = name\gsub '([^%w])', '%%%1' | |
103 | ||
104 | local file_name | |
105 | for entry_name in lfs.dir @root .. path | |
106 | if (entry_name\match "^#{name}$") or entry_name\match "^#{name}%.%w+$" | |
107 | if file_name | |
108 | error "two files match #{name}: #{file_name} and #{entry_name}!" | |
109 | file_name = entry_name | |
110 | ||
111 | ||
112 | file_name and @root .. "#{path}/#{file_name}" | |
113 | ||
114 | load_facet: (path, name, type) => | |
115 | filepath = @locate path, name, type | |
116 | return unless filepath | |
117 | file = assert (io.open filepath, 'rb'), "couldn't open facet file '#{filepath}'" | |
118 | with file\read '*all' | |
119 | file\close! | |
120 | ||
121 | create_facet: (path, name, type, blob) => | |
122 | @log "creating facet #{path} | #{name}: #{type}" | |
123 | assert blob, "cant create facet without value!" | |
124 | ||
125 | filepath = @tofp path, name, type | |
126 | if lfs.attributes filepath, 'mode' | |
127 | error "facet file already exists!" | |
128 | ||
129 | file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'" | |
130 | file\write blob | |
131 | file\close! | |
132 | ||
133 | remove_facet: (path, name, type) => | |
134 | @log "removing facet #{path} | #{name}: #{type}" | |
135 | ||
136 | filepath = @locate path, name, type | |
137 | assert filepath, "couldn't locate facet!" | |
138 | assert os.remove filepath | |
139 | ||
140 | rename_facet: (path, name, type, next_name) => | |
141 | @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}" | |
142 | filepath = @locate path, name, type | |
143 | assert filepath, "couldn't locate facet!" | |
144 | assert os.rename filepath, @tofp path, next_name, type | |
145 | ||
146 | update_facet: (path, name, type, blob) => | |
147 | @log "updating facet #{path} | #{name}: #{type}" | |
148 | filepath = @locate path, name, type | |
149 | assert filepath, "couldn't locate facet!" | |
150 | file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'" | |
151 | file\write blob | |
152 | file\close! | |
153 | ||
154 | { | |
155 | :LFSStore | |
156 | } |
0 | sort2 = (a, b) -> | |
1 | {ax, ay}, {bx, by} = a, b | |
2 | "#{ax}//#{ay}" < "#{bx}//#{by}" | |
3 | ||
4 | toseq = (iter) -> | |
5 | with v = [x for x in iter] | |
6 | table.sort v | |
7 | ||
8 | toseq2 = (iter) -> | |
9 | with v = [{x, y} for x, y in iter] | |
10 | table.sort v, sort2 | |
11 | ||
12 | test_driver = (ts) -> | |
13 | randomize false | |
14 | ||
15 | it "starts out empty", -> | |
16 | assert.are.same {}, toseq ts\list_fileders_in! | |
17 | assert.are.same {}, toseq ts\list_all_fileders! | |
18 | ||
19 | it "can't create fileders without missing parents", -> | |
20 | assert.has_error -> | |
21 | ts\create_fileder '/hello', 'world' | |
22 | ||
23 | it "can create root fileders", -> | |
24 | assert.are.same '/hello', ts\create_fileder '', 'hello' | |
25 | assert.are.same {'/hello'}, toseq ts\list_all_fileders! | |
26 | ||
27 | it "can create and list child fileders recursively", -> | |
28 | assert.are.same '/hello/world', | |
29 | ts\create_fileder '/hello', 'world' | |
30 | assert.are.same '/hello/world/again', | |
31 | ts\create_fileder '/hello/world', 'again' | |
32 | ||
33 | assert.are.same {'/hello', '/hello/world', '/hello/world/again'}, | |
34 | toseq ts\list_all_fileders! | |
35 | ||
36 | it "can list immediate children", -> | |
37 | assert.are.same {"/hello"}, toseq ts\list_fileders_in! | |
38 | assert.are.same {"/hello/world"}, toseq ts\list_fileders_in "/hello" | |
39 | assert.are.same {"/hello/world/again"}, toseq ts\list_fileders_in "/hello/world" | |
40 | ||
41 | describe "can create and list facets", -> | |
42 | ts\create_facet '/hello', 'name', 'alpha', 'hello' | |
43 | ts\create_facet '/hello/world', 'name', 'alpha', 'world' | |
44 | ts\create_facet '/hello/world', '', 'text/markdown', '# Helau World!' | |
45 | ||
46 | it "but can't create facet for nonexistant fileders", -> | |
47 | assert.has_error -> ts\create_facet '/hello/orldw', 'name', 'alpha', 'foo' | |
48 | ||
49 | it "but can't create facet without value", -> | |
50 | assert.has_error -> ts\create_facet '/hello/world', 'other', 'alpha', nil | |
51 | ||
52 | it "but can't create facet for duplicate keys", -> | |
53 | assert.has_error -> ts\create_facet '/hello/world', 'name', 'alpha', 'foo' | |
54 | ||
55 | assert.are.same {{'name', 'alpha'}}, toseq2 ts\list_facets '/hello' | |
56 | assert.are.same {{'', 'text/markdown'}, {'name', 'alpha'}}, | |
57 | toseq2 ts\list_facets '/hello/world' | |
58 | ||
59 | it "can load facets", -> | |
60 | assert.are.equal 'hello', ts\load_facet '/hello', 'name', 'alpha' | |
61 | assert.are.equal 'world', ts\load_facet '/hello/world', 'name', 'alpha' | |
62 | assert.are.equal '# Helau World!', ts\load_facet '/hello/world', '', 'text/markdown' | |
63 | assert.is_falsy ts\load_facet '/hello', 'nonexistant', 'facet' | |
64 | ||
65 | it "can rename facets", -> | |
66 | ts\rename_facet '/hello/world', 'name', 'alpha', 'gnome' | |
67 | assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, | |
68 | toseq2 ts\list_facets '/hello/world' | |
69 | assert.are.equal 'world', ts\load_facet '/hello/world', 'gnome', 'alpha' | |
70 | ||
71 | it "can update facets", -> | |
72 | ts\update_facet '/hello/world', '', 'text/markdown', '# Hello World!' | |
73 | assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, | |
74 | toseq2 ts\list_facets '/hello/world' | |
75 | assert.are.equal '# Hello World!', ts\load_facet '/hello/world', '', 'text/markdown' | |
76 | ||
77 | it "can remove facets", -> | |
78 | ts\remove_facet '/hello/world', 'gnome', 'alpha' | |
79 | assert.are.same {{'', 'text/markdown'}}, toseq2 ts\list_facets '/hello/world' | |
80 | ||
81 | assert.has_error -> ts\remove_facet '/hello/world', 'gnome', 'alpha' | |
82 | ||
83 | it "can delete fileders", -> | |
84 | ts\remove_fileder '/hello/world' | |
85 | assert.is_falsy ts\load_facet '/hello/world', 'gnome', 'alpha' | |
86 | assert.are.same {'/hello'}, toseq ts\list_all_fileders! | |
87 | ||
88 | ts\remove_fileder '/hello' | |
89 | assert.are.same {}, toseq ts\list_all_fileders! | |
90 | ||
91 | describe "SQL driver", -> | |
92 | import SQLStore from require 'mmm.mmmfs.drivers.sql' | |
93 | ||
94 | test_driver SQLStore memory: true | |
95 | ||
96 | describe "LFS driver", -> | |
97 | import LFSStore from require 'mmm.mmmfs.drivers.lfs' | |
98 | ||
99 | lfs = require 'lfs' | |
100 | ||
101 | root = os.tmpname! | |
102 | ||
103 | setup -> | |
104 | assert os.remove root | |
105 | assert lfs.mkdir root | |
106 | ||
107 | test_driver LFSStore :root | |
108 | ||
109 | teardown -> | |
110 | assert lfs.rmdir root |
0 | sort2 = (a, b) -> | |
1 | {ax, ay}, {bx, by} = a, b | |
2 | "#{ax}//#{ay}" < "#{bx}//#{by}" | |
3 | ||
4 | toseq = (iter) -> | |
5 | with v = [x for x in iter] | |
6 | table.sort v | |
7 | ||
8 | toseq2 = (iter) -> | |
9 | with v = [{x, y} for x, y in iter] | |
10 | table.sort v, sort2 | |
11 | ||
12 | test_store = (ts) -> | |
13 | randomize false | |
14 | ||
15 | it "starts out empty", -> | |
16 | assert.are.same {}, toseq ts\list_fileders_in! | |
17 | assert.are.same {}, toseq ts\list_all_fileders! | |
18 | ||
19 | it "can't create fileders without missing parents", -> | |
20 | assert.has_error -> | |
21 | ts\create_fileder '/hello', 'world' | |
22 | ||
23 | it "can create root fileders", -> | |
24 | assert.are.same '/hello', ts\create_fileder '', 'hello' | |
25 | assert.are.same {'/hello'}, toseq ts\list_all_fileders! | |
26 | ||
27 | it "can create and list child fileders recursively", -> | |
28 | assert.are.same '/hello/world', | |
29 | ts\create_fileder '/hello', 'world' | |
30 | assert.are.same '/hello/world/again', | |
31 | ts\create_fileder '/hello/world', 'again' | |
32 | ||
33 | assert.are.same {'/hello', '/hello/world', '/hello/world/again'}, | |
34 | toseq ts\list_all_fileders! | |
35 | ||
36 | it "can list immediate children", -> | |
37 | assert.are.same {"/hello"}, toseq ts\list_fileders_in! | |
38 | assert.are.same {"/hello/world"}, toseq ts\list_fileders_in "/hello" | |
39 | assert.are.same {"/hello/world/again"}, toseq ts\list_fileders_in "/hello/world" | |
40 | ||
41 | describe "can create and list facets", -> | |
42 | ts\create_facet '/hello', 'name', 'alpha', 'hello' | |
43 | ts\create_facet '/hello/world', 'name', 'alpha', 'world' | |
44 | ts\create_facet '/hello/world', '', 'text/markdown', '# Helau World!' | |
45 | ||
46 | it "but can't create facet for nonexistant fileders", -> | |
47 | assert.has_error -> ts\create_facet '/hello/orldw', 'name', 'alpha', 'foo' | |
48 | ||
49 | it "but can't create facet without value", -> | |
50 | assert.has_error -> ts\create_facet '/hello/world', 'other', 'alpha', nil | |
51 | ||
52 | it "but can't create facet for duplicate keys", -> | |
53 | assert.has_error -> ts\create_facet '/hello/world', 'name', 'alpha', 'foo' | |
54 | ||
55 | assert.are.same {{'name', 'alpha'}}, toseq2 ts\list_facets '/hello' | |
56 | assert.are.same {{'', 'text/markdown'}, {'name', 'alpha'}}, | |
57 | toseq2 ts\list_facets '/hello/world' | |
58 | ||
59 | it "can load facets", -> | |
60 | assert.are.equal 'hello', ts\load_facet '/hello', 'name', 'alpha' | |
61 | assert.are.equal 'world', ts\load_facet '/hello/world', 'name', 'alpha' | |
62 | assert.are.equal '# Helau World!', ts\load_facet '/hello/world', '', 'text/markdown' | |
63 | assert.is_falsy ts\load_facet '/hello', 'nonexistant', 'facet' | |
64 | ||
65 | it "can rename facets", -> | |
66 | ts\rename_facet '/hello/world', 'name', 'alpha', 'gnome' | |
67 | assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, | |
68 | toseq2 ts\list_facets '/hello/world' | |
69 | assert.are.equal 'world', ts\load_facet '/hello/world', 'gnome', 'alpha' | |
70 | ||
71 | it "can update facets", -> | |
72 | ts\update_facet '/hello/world', '', 'text/markdown', '# Hello World!' | |
73 | assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, | |
74 | toseq2 ts\list_facets '/hello/world' | |
75 | assert.are.equal '# Hello World!', ts\load_facet '/hello/world', '', 'text/markdown' | |
76 | ||
77 | it "can remove facets", -> | |
78 | ts\remove_facet '/hello/world', 'gnome', 'alpha' | |
79 | assert.are.same {{'', 'text/markdown'}}, toseq2 ts\list_facets '/hello/world' | |
80 | ||
81 | assert.has_error -> ts\remove_facet '/hello/world', 'gnome', 'alpha' | |
82 | ||
83 | it "can delete fileders", -> | |
84 | ts\remove_fileder '/hello/world' | |
85 | assert.is_falsy ts\load_facet '/hello/world', 'gnome', 'alpha' | |
86 | assert.are.same {'/hello'}, toseq ts\list_all_fileders! | |
87 | ||
88 | ts\remove_fileder '/hello' | |
89 | assert.are.same {}, toseq ts\list_all_fileders! | |
90 | ||
91 | describe "SQL spec", -> | |
92 | import SQLStore from require 'mmm.mmmfs.stores.sql' | |
93 | ||
94 | test_store SQLStore memory: true | |
95 | ||
96 | describe "FS store", -> | |
97 | import FSStore from require 'mmm.mmmfs.stores.fs' | |
98 | ||
99 | lfs = require 'lfs' | |
100 | ||
101 | root = os.tmpname! | |
102 | ||
103 | setup -> | |
104 | assert os.remove root | |
105 | assert lfs.mkdir root | |
106 | ||
107 | test_store LFSStore :root | |
108 | ||
109 | teardown -> | |
110 | assert lfs.rmdir root |