summaryrefslogtreecommitdiff
path: root/script-beta/fs-utility.lua
diff options
context:
space:
mode:
Diffstat (limited to 'script-beta/fs-utility.lua')
-rw-r--r--script-beta/fs-utility.lua314
1 files changed, 314 insertions, 0 deletions
diff --git a/script-beta/fs-utility.lua b/script-beta/fs-utility.lua
new file mode 100644
index 00000000..14dcb08f
--- /dev/null
+++ b/script-beta/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