From b866465f2f9017d43b2a8ebb2cb889cdce737737 Mon Sep 17 00:00:00 2001 From: s-ol Date: Wed, 9 Oct 2019 13:53:36 +0200 Subject: rename LFS to FS store --- Dockerfile | 2 +- mmm/mmmfs/stores/fs.moon | 156 ++++++++++++++++++++++++++++++++++++++++++++ mmm/mmmfs/stores/init.moon | 10 +-- mmm/mmmfs/stores/lfs.moon | 157 --------------------------------------------- spec/driver_spec.moon | 111 -------------------------------- spec/stores_spec.moon | 111 ++++++++++++++++++++++++++++++++ 6 files changed, 273 insertions(+), 274 deletions(-) create mode 100644 mmm/mmmfs/stores/fs.moon delete mode 100644 mmm/mmmfs/stores/lfs.moon delete mode 100644 spec/driver_spec.moon create mode 100644 spec/stores_spec.moon diff --git a/Dockerfile b/Dockerfile index f8c158b..273043a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,4 +16,4 @@ WORKDIR /code RUN tup init && tup generate --config tup.docker.config build-static.sh && ./build-static.sh EXPOSE 8000 -ENTRYPOINT ["moon", "build/server.moon", "/db.sqlite3", "0.0.0.0", "8000"] +ENTRYPOINT ["moon", "build/server.moon", "sql:/db.sqlite3", "0.0.0.0", "8000"] diff --git a/mmm/mmmfs/stores/fs.moon b/mmm/mmmfs/stores/fs.moon new file mode 100644 index 0000000..41ce729 --- /dev/null +++ b/mmm/mmmfs/stores/fs.moon @@ -0,0 +1,156 @@ +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 FSStore + 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! + +{ + :FSStore +} diff --git a/mmm/mmmfs/stores/init.moon b/mmm/mmmfs/stores/init.moon index 17595fe..381c80b 100644 --- a/mmm/mmmfs/stores/init.moon +++ b/mmm/mmmfs/stores/init.moon @@ -1,7 +1,7 @@ require = relative ..., 0 -- instantiate a store from a CLI arg --- e.g.: sql, lfs:/path/to/root, sql:MEMORY, sql:db.sqlite3 +-- e.g.: sql, fs:/path/to/root, sql:MEMORY, sql:db.sqlite3 get_store = (args='sql', opts={verbose: true}) -> type, arg = args\match '(%w+):(.*)' type = arg unless type @@ -13,19 +13,19 @@ get_store = (args='sql', opts={verbose: true}) -> if arg == 'MEMORY' opts.memory = true else - opts.name = arg + opts.file = arg SQLStore opts - when 'lfs' - import LFSStore from require '.lfs' + when 'fs' + import LFSStore from require '.fs' opts.root = arg LFSStore opts else - warn "unknown or missing value for STORE: valid types values are sql, lfs" + warn "unknown or missing value for STORE: valid types values are sql, fs" os.exit 1 { diff --git a/mmm/mmmfs/stores/lfs.moon b/mmm/mmmfs/stores/lfs.moon deleted file mode 100644 index a90b55a..0000000 --- a/mmm/mmmfs/stores/lfs.moon +++ /dev/null @@ -1,157 +0,0 @@ -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/spec/driver_spec.moon b/spec/driver_spec.moon deleted file mode 100644 index 918f620..0000000 --- a/spec/driver_spec.moon +++ /dev/null @@ -1,111 +0,0 @@ -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 - -test_driver = (ts) -> - randomize false - - it "starts out empty", -> - assert.are.same {}, toseq ts\list_fileders_in! - assert.are.same {}, toseq ts\list_all_fileders! - - it "can't create fileders without missing parents", -> - assert.has_error -> - ts\create_fileder '/hello', 'world' - - it "can create root fileders", -> - assert.are.same '/hello', ts\create_fileder '', 'hello' - assert.are.same {'/hello'}, toseq ts\list_all_fileders! - - it "can create and list child fileders recursively", -> - assert.are.same '/hello/world', - ts\create_fileder '/hello', 'world' - assert.are.same '/hello/world/again', - ts\create_fileder '/hello/world', 'again' - - assert.are.same {'/hello', '/hello/world', '/hello/world/again'}, - toseq ts\list_all_fileders! - - it "can list immediate children", -> - assert.are.same {"/hello"}, toseq ts\list_fileders_in! - assert.are.same {"/hello/world"}, toseq ts\list_fileders_in "/hello" - assert.are.same {"/hello/world/again"}, toseq ts\list_fileders_in "/hello/world" - - describe "can create and list facets", -> - ts\create_facet '/hello', 'name', 'alpha', 'hello' - ts\create_facet '/hello/world', 'name', 'alpha', 'world' - ts\create_facet '/hello/world', '', 'text/markdown', '# Helau World!' - - it "but can't create facet for nonexistant fileders", -> - assert.has_error -> ts\create_facet '/hello/orldw', 'name', 'alpha', 'foo' - - it "but can't create facet without value", -> - assert.has_error -> ts\create_facet '/hello/world', 'other', 'alpha', nil - - 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' - assert.are.same {{'', 'text/markdown'}, {'name', 'alpha'}}, - toseq2 ts\list_facets '/hello/world' - - it "can load facets", -> - assert.are.equal 'hello', ts\load_facet '/hello', 'name', 'alpha' - assert.are.equal 'world', ts\load_facet '/hello/world', 'name', 'alpha' - assert.are.equal '# Helau World!', ts\load_facet '/hello/world', '', 'text/markdown' - assert.is_falsy ts\load_facet '/hello', 'nonexistant', 'facet' - - it "can rename facets", -> - ts\rename_facet '/hello/world', 'name', 'alpha', 'gnome' - assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, - toseq2 ts\list_facets '/hello/world' - assert.are.equal 'world', ts\load_facet '/hello/world', 'gnome', 'alpha' - - it "can update facets", -> - ts\update_facet '/hello/world', '', 'text/markdown', '# Hello World!' - assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, - toseq2 ts\list_facets '/hello/world' - assert.are.equal '# Hello World!', ts\load_facet '/hello/world', '', 'text/markdown' - - it "can remove facets", -> - ts\remove_facet '/hello/world', 'gnome', 'alpha' - assert.are.same {{'', 'text/markdown'}}, toseq2 ts\list_facets '/hello/world' - - assert.has_error -> ts\remove_facet '/hello/world', 'gnome', 'alpha' - - it "can delete fileders", -> - ts\remove_fileder '/hello/world' - assert.is_falsy ts\load_facet '/hello/world', 'gnome', 'alpha' - assert.are.same {'/hello'}, toseq ts\list_all_fileders! - - 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 diff --git a/spec/stores_spec.moon b/spec/stores_spec.moon new file mode 100644 index 0000000..3997ded --- /dev/null +++ b/spec/stores_spec.moon @@ -0,0 +1,111 @@ +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 + +test_store = (ts) -> + randomize false + + it "starts out empty", -> + assert.are.same {}, toseq ts\list_fileders_in! + assert.are.same {}, toseq ts\list_all_fileders! + + it "can't create fileders without missing parents", -> + assert.has_error -> + ts\create_fileder '/hello', 'world' + + it "can create root fileders", -> + assert.are.same '/hello', ts\create_fileder '', 'hello' + assert.are.same {'/hello'}, toseq ts\list_all_fileders! + + it "can create and list child fileders recursively", -> + assert.are.same '/hello/world', + ts\create_fileder '/hello', 'world' + assert.are.same '/hello/world/again', + ts\create_fileder '/hello/world', 'again' + + assert.are.same {'/hello', '/hello/world', '/hello/world/again'}, + toseq ts\list_all_fileders! + + it "can list immediate children", -> + assert.are.same {"/hello"}, toseq ts\list_fileders_in! + assert.are.same {"/hello/world"}, toseq ts\list_fileders_in "/hello" + assert.are.same {"/hello/world/again"}, toseq ts\list_fileders_in "/hello/world" + + describe "can create and list facets", -> + ts\create_facet '/hello', 'name', 'alpha', 'hello' + ts\create_facet '/hello/world', 'name', 'alpha', 'world' + ts\create_facet '/hello/world', '', 'text/markdown', '# Helau World!' + + it "but can't create facet for nonexistant fileders", -> + assert.has_error -> ts\create_facet '/hello/orldw', 'name', 'alpha', 'foo' + + it "but can't create facet without value", -> + assert.has_error -> ts\create_facet '/hello/world', 'other', 'alpha', nil + + 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' + assert.are.same {{'', 'text/markdown'}, {'name', 'alpha'}}, + toseq2 ts\list_facets '/hello/world' + + it "can load facets", -> + assert.are.equal 'hello', ts\load_facet '/hello', 'name', 'alpha' + assert.are.equal 'world', ts\load_facet '/hello/world', 'name', 'alpha' + assert.are.equal '# Helau World!', ts\load_facet '/hello/world', '', 'text/markdown' + assert.is_falsy ts\load_facet '/hello', 'nonexistant', 'facet' + + it "can rename facets", -> + ts\rename_facet '/hello/world', 'name', 'alpha', 'gnome' + assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, + toseq2 ts\list_facets '/hello/world' + assert.are.equal 'world', ts\load_facet '/hello/world', 'gnome', 'alpha' + + it "can update facets", -> + ts\update_facet '/hello/world', '', 'text/markdown', '# Hello World!' + assert.are.same {{'', 'text/markdown'}, {'gnome', 'alpha'}}, + toseq2 ts\list_facets '/hello/world' + assert.are.equal '# Hello World!', ts\load_facet '/hello/world', '', 'text/markdown' + + it "can remove facets", -> + ts\remove_facet '/hello/world', 'gnome', 'alpha' + assert.are.same {{'', 'text/markdown'}}, toseq2 ts\list_facets '/hello/world' + + assert.has_error -> ts\remove_facet '/hello/world', 'gnome', 'alpha' + + it "can delete fileders", -> + ts\remove_fileder '/hello/world' + assert.is_falsy ts\load_facet '/hello/world', 'gnome', 'alpha' + assert.are.same {'/hello'}, toseq ts\list_all_fileders! + + ts\remove_fileder '/hello' + assert.are.same {}, toseq ts\list_all_fileders! + +describe "SQL spec", -> + import SQLStore from require 'mmm.mmmfs.stores.sql' + + test_store SQLStore memory: true + +describe "FS store", -> + import FSStore from require 'mmm.mmmfs.stores.fs' + + lfs = require 'lfs' + + root = os.tmpname! + + setup -> + assert os.remove root + assert lfs.mkdir root + + test_store LFSStore :root + + teardown -> + assert lfs.rmdir root -- cgit v1.2.3