diff options
Diffstat (limited to 'script-beta/src/fs-utility.lua')
-rw-r--r-- | script-beta/src/fs-utility.lua | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/script-beta/src/fs-utility.lua b/script-beta/src/fs-utility.lua new file mode 100644 index 00000000..14dcb08f --- /dev/null +++ b/script-beta/src/fs-utility.lua @@ -0,0 +1,314 @@ +local fs = require 'bee.filesystem' +local platform = require 'bee.platform' + +local type = type +local ioOpen = io.open +local pcall = pcall +local pairs = pairs +local setmetatable = setmetatable +local next = next + +_ENV = nil + +local m = {} +--- 读取文件 +---@param path string +function m.loadFile(path) + if type(path) ~= 'string' then + path = path:string() + end + local f, e = ioOpen(path, 'rb') + if not f then + return nil, e + end + if f:read(3) ~= '\xEF\xBB\xBF' then + f:seek("set") + end + local buf = f:read 'a' + f:close() + return buf +end + +--- 写入文件 +---@param path string +---@param content string +function m.saveFile(path, content) + if type(path) ~= 'string' then + path = path:string() + end + local f, e = ioOpen(path, "wb") + + if f then + f:write(content) + f:close() + return true + else + return false, e + end +end + +local function buildOptional(optional) + optional = optional or {} + optional.add = optional.add or {} + optional.del = optional.del or {} + optional.mod = optional.mod or {} + optional.err = optional.err or {} + return optional +end + +local function fsAbsolute(path, optional) + if type(path) == 'string' then + local suc, res = pcall(fs.path, path) + if not suc then + optional.err[#optional.err+1] = res + return nil + end + path = res + end + local suc, res = pcall(fs.absolute, path) + if not suc then + optional.err[#optional.err+1] = res + return nil + end + return res +end + +local function fsIsDirectory(path, optional) + local suc, res = pcall(fs.is_directory, path) + if not suc then + optional.err[#optional.err+1] = res + return false + end + return res +end + +local function fsRemove(path, optional) + local suc, res = pcall(fs.remove, path) + if not suc then + optional.err[#optional.err+1] = res + end + optional.del[#optional.del+1] = path:string() +end + +local function fsExists(path, optional) + local suc, res = pcall(fs.exists, path) + if not suc then + optional.err[#optional.err+1] = res + return false + end + return res +end + +local function fsCopy(source, target, optional) + local suc, res = pcall(fs.copy_file, source, target, true) + if not suc then + optional.err[#optional.err+1] = res + return false + end + return true +end + +local function fsCreateDirectories(path, optional) + local suc, res = pcall(fs.create_directories, path) + if not suc then + optional.err[#optional.err+1] = res + return false + end + return true +end + +local function fileRemove(path, optional) + if optional.onRemove and optional.onRemove(path) == false then + return + end + if fsIsDirectory(path, optional) then + for child in path:list_directory() do + fileRemove(child, optional) + end + end + if fsRemove(path, optional) then + optional.del[#optional.del+1] = path:string() + end +end + +local function fileCopy(source, target, optional) + local isDir1 = fsIsDirectory(source, optional) + local isDir2 = fsIsDirectory(target, optional) + local isExists = fsExists(target, optional) + if isDir1 then + if isDir2 or fsCreateDirectories(target) then + for filePath in source:list_directory() do + local name = filePath:filename() + fileCopy(filePath, target / name, optional) + end + end + else + if isExists and not isDir2 then + local buf1, err1 = m.loadFile(source) + local buf2, err2 = m.loadFile(target) + if buf1 and buf2 then + if buf1 ~= buf2 then + if fsCopy(source, target, optional) then + optional.mod[#optional.mod+1] = target:string() + end + end + else + if not buf1 then + optional.err[#optional.err+1] = err1 + end + if not buf2 then + optional.err[#optional.err+1] = err2 + end + end + else + if fsCopy(source, target, optional) then + optional.add[#optional.add+1] = target:string() + end + end + end +end + +local function fileSync(source, target, optional) + local isDir1 = fsIsDirectory(source, optional) + local isDir2 = fsIsDirectory(target, optional) + local isExists = fsExists(target, optional) + if isDir1 then + if isDir2 then + local fileList = m.fileList() + for filePath in target:list_directory() do + fileList[filePath] = true + end + for filePath in source:list_directory() do + local name = filePath:filename() + local targetPath = target / name + fileSync(filePath, targetPath, optional) + fileList[targetPath] = nil + end + for path in pairs(fileList) do + fileRemove(path, optional) + end + else + if isExists then + fileRemove(target, optional) + end + if fsCreateDirectories(target) then + for filePath in source:list_directory() do + local name = filePath:filename() + fileCopy(filePath, target / name, optional) + end + end + end + else + if isDir2 then + fileRemove(target, optional) + end + if isExists then + local buf1, err1 = m.loadFile(source) + local buf2, err2 = m.loadFile(target) + if buf1 and buf2 then + if buf1 ~= buf2 then + if fsCopy(source, target, optional) then + optional.mod[#optional.mod+1] = target:string() + end + end + else + if not buf1 then + optional.err[#optional.err+1] = err1 + end + if not buf2 then + optional.err[#optional.err+1] = err2 + end + end + else + if fsCopy(source, target, optional) then + optional.add[#optional.add+1] = target:string() + end + end + end +end + +--- 文件列表 +function m.fileList(optional) + optional = optional or buildOptional(optional) + local os = platform.OS + local keyMap = {} + local fileList = {} + local function computeKey(path) + path = fsAbsolute(path, optional) + if not path then + return nil + end + local key + if os == 'Windows' then + key = path:string():lower() + else + key = path:string() + end + return key + end + return setmetatable({}, { + __index = function (_, path) + local key = computeKey(path) + return fileList[key] + end, + __newindex = function (_, path, value) + local key = computeKey(path) + if not key then + return + end + if value == nil then + keyMap[key] = nil + else + keyMap[key] = path + fileList[key] = value + end + end, + __pairs = function () + local key, path + return function () + key, path = next(keyMap, key) + return path, fileList[key] + end + end, + }) +end + +--- 删除文件(夹) +function m.fileRemove(path, optional) + optional = buildOptional(optional) + path = fsAbsolute(path, optional) + + fileRemove(path, optional) + + return optional +end + +--- 复制文件(夹) +---@param source string +---@param target string +---@return table +function m.fileCopy(source, target, optional) + optional = buildOptional(optional) + source = fsAbsolute(source, optional) + target = fsAbsolute(target, optional) + + fileCopy(source, target, optional) + + return optional +end + +--- 同步文件(夹) +---@param source string +---@param target string +---@return table +function m.fileSync(source, target, optional) + optional = buildOptional(optional) + source = fsAbsolute(source, optional) + target = fsAbsolute(target, optional) + + fileSync(source, target, optional) + + return optional +end + +return m |