git.s-ol.nu mmm / a62f63b mmm / mmmfs / stores / fs.moon
a62f63b

Tree @a62f63b (Download .tar.gz)

fs.moon @a62f63braw · history · blame

require = relative ..., 1
lfs = require 'lfs'
import Store from require '.'

-- 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 extends Store
  new: (opts = {}) =>
    super opts

    opts.root or= 'root'

    -- ensure path doesnt end with a slash
    @root = opts.root\match '^(.-)/?$'
    @log "opening '#{opts.root}'..."

  -- fileders
  list_fileders_in: (path='') =>
    entries = {}
    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'
        continue

      entries[entry_name] = "#{path}/#{entry_name}"

    sorted = {}

    order_file = @root .. "#{path}/$order"
    if 'file' == lfs.attributes order_file, 'mode'
      for line in io.lines order_file
        path = assert entries[line], "entry in $order but not on disk: #{line}"
        table.insert sorted, path
        sorted[line] = true

    entries = [path for entry, path in pairs entries when not sorted[entry]]
    table.sort entries
    for path in *entries
      table.insert sorted, path

    coroutine.wrap ->
      for path in *sorted
        coroutine.yield path

  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}"
        continue if entry_name == '$order'
        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
}