filesystem.lua
local async = require("async")
local lgi = require("lgi")
local GLib = lgi.GLib
local Gio = lgi.Gio
local File = require("lgi-async-extra.file")
local filesystem = {}
local function file_arg(arg)
if type(arg) == "string" then
return Gio.File.new_for_path(arg)
elseif File.is_instance(arg) then
return arg._private.f
else
return arg
end
end
function filesystem.make_directory(path, cb)
local f = file_arg(path)
f:make_directory_async(GLib.PRIORITY_DEFAULT, nil, function(_, token)
local _, err = f:make_directory_finish(token)
cb(err)
end)
end
function filesystem.iterate_contents(dir, iteratee, options, cb)
if type(options) == "function" then
cb = options
options = {}
end
local attributes = options.attributes or "standard::type"
local priority = GLib.PRIORITY_DEFAULT
local BUFFER_SIZE = 50
local f = file_arg(dir)
async.dag({
enumerator = function(_, cb)
f:enumerate_children_async(attributes, Gio.FileQueryInfoFlags.NONE, priority, nil, function(_, token)
local enumerator, err = f:enumerate_children_finish(token)
cb(err, enumerator)
end)
end,
iterate = { "enumerator", function(results, cb)
local enumerator = table.unpack(results.enumerator)
local function iterate(cb_iterate)
enumerator:next_files_async(BUFFER_SIZE, priority, nil, function(_, token)
local infos, err = enumerator:next_files_finish(token)
if err or #infos == 0 then
return cb_iterate(err, infos)
end
local tasks = {}
for _, info in ipairs(infos) do
local path = string.format("%s/%s", f:get_path(), info:get_name())
local f = File.new_for_path(path)
if Gio.FileType[info:get_file_type()] == Gio.FileType.DIRECTORY then
if options.list_directories ~= false then
table.insert(tasks, async.callback(nil, iteratee, info))
end
table.insert(tasks, async.callback(f, filesystem.iterate_contents, iteratee, options))
else
table.insert(tasks, async.callback(nil, iteratee, info))
end
end
async.all(tasks, function(err)
cb_iterate(err, infos)
end)
end)
end
local function check(infos, cb_check)
cb_check(nil, #infos > 0)
end
async.do_while(iterate, check, function(err)
cb(err)
end)
end },
}, function(err, results)
local enumerator = table.unpack(results.enumerator)
enumerator:close_async(priority, nil, function(_, token)
local _, err_inner = enumerator:close_finish(token)
if err and err.code == Gio.IOErrorEnum[Gio.IOErrorEnum.CLOSED] then
err_inner = nil
end
cb(err or err_inner)
end)
end)
end
function filesystem.list_contents(dir, attributes, cb)
if type(attributes) == "function" then
cb = attributes
attributes = "standard::type"
end
local priority = GLib.PRIORITY_DEFAULT
local BUFFER_SIZE = 50
local f = file_arg(dir)
async.dag({
enumerator = function(_, cb)
f:enumerate_children_async(attributes, Gio.FileQueryInfoFlags.NONE, priority, nil, function(_, token)
local enumerator, err = f:enumerate_children_finish(token)
cb(err, enumerator)
end)
end,
list = { "enumerator", function(results, cb)
local enumerator = table.unpack(results.enumerator)
local list = {}
local function iterate(cb_iterate)
enumerator:next_files_async(BUFFER_SIZE, priority, nil, function(_, token)
local infos, err = enumerator:next_files_finish(token)
if infos and #infos > 0 then
for _, info in ipairs(infos) do
table.insert(list, info)
end
end
cb_iterate(err, infos)
end)
end
local function check(infos, cb_check)
cb_check(nil, #infos > 0)
end
async.do_while(iterate, check, function(err)
cb(err, list)
end)
end },
}, function(err, results)
local enumerator = table.unpack(results.enumerator)
local list = results.list and table.unpack(results.list)
enumerator:close_async(priority, nil, function(_, token)
local _, err_inner = enumerator:close_finish(token)
if err and err.code == Gio.IOErrorEnum[Gio.IOErrorEnum.CLOSED] then
err_inner = nil
end
cb(err or err_inner, list)
end)
end)
end
function filesystem.remove_directory(dir, cb)
local priority = GLib.PRIORITY_DEFAULT
local f = file_arg(dir)
local BUFFER_SIZE = 50
async.dag({
enumerator = function(_, cb)
f:enumerate_children_async("standard::type", Gio.FileQueryInfoFlags.NONE, priority, nil, function(_, token)
local enumerator, err = f:enumerate_children_finish(token)
cb(err, enumerator)
end)
end,
iterate = { "enumerator", function(results, cb)
local enumerator = table.unpack(results.enumerator)
local function iterate(cb_iterate)
enumerator:next_files_async(BUFFER_SIZE, priority, nil, function(_, token)
local infos, err = enumerator:next_files_finish(token)
if err or #infos == 0 then
return cb(err, infos)
end
local tasks = {}
for _, info in ipairs(infos) do
local path = string.format("%s/%s", f:get_path(), info:get_name())
local f = File.new_for_path(path)
if Gio.FileType[info:get_file_type()] == Gio.FileType.DIRECTORY then
table.insert(tasks, async.callback(f, filesystem.remove_directory))
else
table.insert(tasks, async.callback(f, f.delete))
end
end
async.all(tasks, cb_iterate)
end)
end
local function check(infos, cb_check)
cb_check(nil, #infos > 0)
end
async.do_while(iterate, check, cb)
end },
delete = { "iterate", function(_, cb)
f:delete_async(priority, nil, function(_, token)
local _, err = f:delete_finish(token)
cb(err)
end)
end },
}, function(err, results)
local enumerator = table.unpack(results.enumerator)
enumerator:close_async(priority, nil, function(_, token)
local _, err_inner = enumerator:close_finish(token)
if err and err.code == Gio.IOErrorEnum[Gio.IOErrorEnum.CLOSED] then
err_inner = nil
end
cb(err or err_inner)
end)
end)
end
return filesystem