aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2019-10-09 11:06:44 +0000
committers-ol <s-ol@users.noreply.github.com>2019-10-09 11:06:44 +0000
commit86bbe805a7ec49a8b891412713ea43d6e46d0d73 (patch)
treed2f86a3934ce257cee5a5295f6c6a61d71ec87eb
parentadd ba_log entry 2019-10-08 (diff)
downloadmmm-86bbe805a7ec49a8b891412713ea43d6e46d0d73.tar.gz
mmm-86bbe805a7ec49a8b891412713ea43d6e46d0d73.zip
add lfs driver, spec
-rw-r--r--mmm/mmmfs/drivers/lfs.moon157
-rw-r--r--mmm/mmmfs/drivers/sql.moon5
-rw-r--r--mmm/mmmfs/drivers/zip.moon59
-rw-r--r--spec/driver_spec.moon45
4 files changed, 194 insertions, 72 deletions
diff --git a/mmm/mmmfs/drivers/lfs.moon b/mmm/mmmfs/drivers/lfs.moon
new file mode 100644
index 0000000..a90b55a
--- /dev/null
+++ b/mmm/mmmfs/drivers/lfs.moon
@@ -0,0 +1,157 @@
+lfs = require 'lfs'
+
+-- split filename into dirname + basename
+dir_base = (path) ->
+ dir, base = path\match '(.-)([^/]-)$'
+ if dir and #dir > 0
+ dir = dir\sub 1, #dir - 1
+
+ dir, base
+
+
+class LFSStore
+ new: (opts = {}) =>
+ opts.root or= 'root'
+ opts.verbose or= false
+
+ if not opts.verbose
+ @log = ->
+
+ -- ensure path doesnt end with a slash
+ @root = opts.root\match '^(.-)/?$'
+ @log "opening '#{opts.root}'..."
+
+ log: (...) =>
+ print "[DB]", ...
+
+ -- fileders
+ list_fileders_in: (path='') =>
+ coroutine.wrap ->
+ for entry_name in lfs.dir @root .. path
+ continue if '.' == entry_name\sub 1, 1
+ entry_path = @root .. "#{path}/#{entry_name}"
+ if 'directory' == lfs.attributes entry_path, 'mode'
+ coroutine.yield "#{path}/#{entry_name}"
+
+ list_all_fileders: (path='') =>
+ coroutine.wrap ->
+ for path in @list_fileders_in path
+ coroutine.yield path
+ for p in @list_all_fileders path
+ coroutine.yield p
+
+ create_fileder: (parent, name) =>
+ @log "creating fileder #{path}"
+ path = "#{parent}/#{name}"
+ assert lfs.mkdir @root .. path
+ path
+
+ remove_fileder: (path) =>
+ @log "removing fileder #{path}"
+
+ rmdir = (path) ->
+ for file in lfs.dir path
+ continue if '.' == file\sub 1, 1
+
+ file_path = "#{path}/#{file}"
+ switch lfs.attributes file_path, 'mode'
+ when 'file'
+ assert os.remove file_path
+ when 'directory'
+ assert rmdir file_path
+
+ lfs.rmdir path
+
+ rmdir @root .. path
+
+ rename_fileder: (path, next_name) =>
+ @log "renaming fileder #{path} -> '#{next_name}'"
+ parent, name = dir_base path
+ assert os.rename path, @root .. "#{parent}/#{next_name}"
+
+ move_fileder: (path, next_parent) =>
+ @log "moving fileder #{path} -> #{next_parent}/"
+ parent, name = dir_base path
+ assert os.rename @root .. path, @root .. "#{next_parent}/#{name}"
+
+ -- facets
+ list_facets: (path) =>
+ coroutine.wrap ->
+ for entry_name in lfs.dir @root .. path
+ entry_path = "#{@root .. path}/#{entry_name}"
+ if 'file' == lfs.attributes entry_path, 'mode'
+ entry_name = (entry_name\match '(.*)%.%w+') or entry_name
+ entry_name = entry_name\gsub '%$', '/'
+ name, type = entry_name\match '(%w+): *(.+)'
+ if not name
+ name = ''
+ type = entry_name
+
+ coroutine.yield name, type
+
+ tofp: (path, name, type) =>
+ type = "#{name}: #{type}" if #name > 0
+ type = type\gsub '%/', '$'
+ @root .. "#{path}/#{type}"
+
+ locate: (path, name, type) =>
+ return unless lfs.attributes @root .. path, 'mode'
+
+ type = type\gsub '%/', '$'
+ name = "#{name}: " if #name > 0
+ name = name .. type
+ name = name\gsub '([^%w])', '%%%1'
+
+ local file_name
+ for entry_name in lfs.dir @root .. path
+ if (entry_name\match "^#{name}$") or entry_name\match "^#{name}%.%w+$"
+ if file_name
+ error "two files match #{name}: #{file_name} and #{entry_name}!"
+ file_name = entry_name
+
+
+ file_name and @root .. "#{path}/#{file_name}"
+
+ load_facet: (path, name, type) =>
+ filepath = @locate path, name, type
+ return unless filepath
+ file = assert (io.open filepath, 'rb'), "couldn't open facet file '#{filepath}'"
+ with file\read '*all'
+ file\close!
+
+ create_facet: (path, name, type, blob) =>
+ @log "creating facet #{path} | #{name}: #{type}"
+ assert blob, "cant create facet without value!"
+
+ filepath = @tofp path, name, type
+ if lfs.attributes filepath, 'mode'
+ error "facet file already exists!"
+
+ file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'"
+ file\write blob
+ file\close!
+
+ remove_facet: (path, name, type) =>
+ @log "removing facet #{path} | #{name}: #{type}"
+
+ filepath = @locate path, name, type
+ assert filepath, "couldn't locate facet!"
+ assert os.remove filepath
+
+ rename_facet: (path, name, type, next_name) =>
+ @log "renaming facet #{path} | #{name}: #{type} -> #{next_name}"
+ filepath = @locate path, name, type
+ assert filepath, "couldn't locate facet!"
+ assert os.rename filepath, @tofp path, next_name, type
+
+ update_facet: (path, name, type, blob) =>
+ @log "updating facet #{path} | #{name}: #{type}"
+ filepath = @locate path, name, type
+ assert filepath, "couldn't locate facet!"
+ file = assert (io.open filepath, 'wb'), "couldn't open facet file '#{filepath}'"
+ file\write blob
+ file\close!
+
+{
+ :LFSStore
+}
diff --git a/mmm/mmmfs/drivers/sql.moon b/mmm/mmmfs/drivers/sql.moon
index 9337dd8..490eade 100644
--- a/mmm/mmmfs/drivers/sql.moon
+++ b/mmm/mmmfs/drivers/sql.moon
@@ -1,4 +1,5 @@
sqlite = require 'sqlite3'
+root = os.tmpname!
class SQLStore
new: (opts = {}) =>
@@ -96,6 +97,7 @@ class SQLStore
OR path = :path', path
rename_fileder: (path, next_name) =>
+ @log "renaming fileder #{path} -> '#{next_name}'"
error 'not implemented'
@exec 'UPDATE fileder
@@ -105,7 +107,8 @@ class SQLStore
-- @TODO: rename all children, child-children...
- move_fileder: (path, new_parent) =>
+ move_fileder: (path, next_parent) =>
+ @log "moving fileder #{path} -> #{next_parent}/"
error 'not implemented'
-- @TODO: remove all children, child-children...
diff --git a/mmm/mmmfs/drivers/zip.moon b/mmm/mmmfs/drivers/zip.moon
deleted file mode 100644
index c6417e2..0000000
--- a/mmm/mmmfs/drivers/zip.moon
+++ /dev/null
@@ -1,59 +0,0 @@
-require = relative ..., 1
-import Fileder, Key from require '.fileder'
-zip = require 'brimworks.zip'
-
--- split filename into dirname + basename
-dir_base = (path) ->
- dir, base = path\match '(.-)([^/]-)$'
- if dir and #dir > 0
- dir = dir\sub 1, #dir - 1
-
- dir, base
-
--- insert into array unless contained
-table_add = (tbl, entry) ->
- for _, v in ipairs tbl
- if v == entry
- return
-
- table.insert tbl, entry
-
--- strip facet formatting
-load_facet = (filename) ->
- key = (filename\match '(.*)%.%w+') or filename
- key = Key key\gsub '%$', '/'
- key.filename = filename
-
- key
-
-load_tree = (file='root.zip') ->
- archive = zip.open file
-
- fileders = setmetatable {},
- __index: (path) =>
- with val = Fileder {}
- .path = path
- rawset @, path, val
-
- fileders['/root'].facets['name: alpha'] = -> 'root'
-
- for i = 1, #archive
- { :name, :size } = archive\stat i
-
- path, facet = dir_base "/#{name}"
- parent, name = dir_base path
-
- key = load_facet facet
-
- this = fileders[path]
- this.facets['name: alpha'] = -> name
- this.facets[key] = ->
- file = archive\open i
- with file\read size
- file\close!
-
- table_add fileders[parent].children, this
-
- fileders['/root']
-
-{ :load_tree }
diff --git a/spec/driver_spec.moon b/spec/driver_spec.moon
index 379dcac..918f620 100644
--- a/spec/driver_spec.moon
+++ b/spec/driver_spec.moon
@@ -1,17 +1,17 @@
-import SQLStore from require 'mmm.mmmfs.drivers.sql'
-
sort2 = (a, b) ->
{ax, ay}, {bx, by} = a, b
"#{ax}//#{ay}" < "#{bx}//#{by}"
-toseq = (iter) -> with v = [x for x in iter]
- table.sort v
-toseq2 = (iter) -> with v = [{x, y} for x, y in iter]
- table.sort v, sort2
-describe "sql driver", ->
- randomize false
+toseq = (iter) ->
+ with v = [x for x in iter]
+ table.sort v
+
+toseq2 = (iter) ->
+ with v = [{x, y} for x, y in iter]
+ table.sort v, sort2
- ts = SQLStore memory: true
+test_driver = (ts) ->
+ randomize false
it "starts out empty", ->
assert.are.same {}, toseq ts\list_fileders_in!
@@ -44,13 +44,13 @@ describe "sql driver", ->
ts\create_facet '/hello/world', 'name', 'alpha', 'world'
ts\create_facet '/hello/world', '', 'text/markdown', '# Helau World!'
- it "can't create facet for nonexistant fileders", ->
+ it "but can't create facet for nonexistant fileders", ->
assert.has_error -> ts\create_facet '/hello/orldw', 'name', 'alpha', 'foo'
- it "can't create facet without value", ->
+ it "but can't create facet without value", ->
assert.has_error -> ts\create_facet '/hello/world', 'other', 'alpha', nil
- it "can't create facet for duplicate keys", ->
+ it "but can't create facet for duplicate keys", ->
assert.has_error -> ts\create_facet '/hello/world', 'name', 'alpha', 'foo'
assert.are.same {{'name', 'alpha'}}, toseq2 ts\list_facets '/hello'
@@ -88,3 +88,24 @@ describe "sql driver", ->
ts\remove_fileder '/hello'
assert.are.same {}, toseq ts\list_all_fileders!
+
+describe "SQL driver", ->
+ import SQLStore from require 'mmm.mmmfs.drivers.sql'
+
+ test_driver SQLStore memory: true
+
+describe "LFS driver", ->
+ import LFSStore from require 'mmm.mmmfs.drivers.lfs'
+
+ lfs = require 'lfs'
+
+ root = os.tmpname!
+
+ setup ->
+ assert os.remove root
+ assert lfs.mkdir root
+
+ test_driver LFSStore :root
+
+ teardown ->
+ assert lfs.rmdir root