local Path = require "mason-core.path" local a = require "mason-core.async" local log = require "mason-core.log" local settings = require "mason.settings" local function make_module(uv) local M = {} ---@param path string function M.fstat(path) log.trace("fs: fstat", path) local fd = uv.fs_open(path, "r", 438) local fstat = uv.fs_fstat(fd) uv.fs_close(fd) return fstat end ---@param path string function M.file_exists(path) log.trace("fs: file_exists", path) local ok, fstat = pcall(M.fstat, path) if not ok then return false end return fstat.type == "file" end ---@param path string function M.dir_exists(path) log.trace("fs: dir_exists", path) local ok, fstat = pcall(M.fstat, path) if not ok then return false end return fstat.type == "directory" end ---@param path string function M.rmrf(path) assert( Path.is_subdirectory(settings.current.install_root_dir, path), ("Refusing to rmrf %q which is outside of the allowed boundary %q. Please report this error at https://github.com/williamboman/mason.nvim/issues/new"):format( path, settings.current.install_root_dir ) ) log.debug("fs: rmrf", path) if vim.in_fast_event() then a.scheduler() end if vim.fn.delete(path, "rf") ~= 0 then log.debug "fs: rmrf failed" error(("rmrf: Could not remove directory %q."):format(path)) end end ---@param path string function M.unlink(path) log.debug("fs: unlink", path) uv.fs_unlink(path) end ---@param path string function M.mkdir(path) log.debug("fs: mkdir", path) uv.fs_mkdir(path, 493) -- 493(10) == 755(8) end ---@param path string function M.mkdirp(path) log.debug("fs: mkdirp", path) if vim.in_fast_event() then a.scheduler() end if vim.fn.mkdir(path, "p") ~= 1 then log.debug "fs: mkdirp failed" error(("mkdirp: Could not create directory %q."):format(path)) end end ---@param path string ---@param new_path string function M.rename(path, new_path) log.debug("fs: rename", path, new_path) uv.fs_rename(path, new_path) end ---@param path string ---@param new_path string ---@param flags table? { excl?: boolean, ficlone?: boolean, ficlone_force?: boolean } function M.copy_file(path, new_path, flags) log.debug("fs: copy_file", path, new_path, flags) uv.fs_copyfile(path, new_path, flags) end ---@param path string ---@param contents string ---@param flags string? Defaults to "w". function M.write_file(path, contents, flags) log.trace("fs: write_file", path) local fd = uv.fs_open(path, flags or "w", 438) uv.fs_write(fd, contents, -1) uv.fs_close(fd) end ---@param path string ---@param contents string function M.append_file(path, contents) M.write_file(path, contents, "a") end ---@param path string function M.read_file(path) log.trace("fs: read_file", path) local fd = uv.fs_open(path, "r", 438) local fstat = uv.fs_fstat(fd) local contents = uv.fs_read(fd, fstat.size, 0) uv.fs_close(fd) return contents end ---@alias ReaddirEntry {name: string, type: string} ---@param path string: The full path to the directory to read. ---@return ReaddirEntry[] function M.readdir(path) log.trace("fs: fs_opendir", path) local dir = assert(vim.loop.fs_opendir(path, nil, 25)) local all_entries = {} local exhausted = false repeat local entries = uv.fs_readdir(dir) log.trace("fs: fs_readdir", path, entries) if entries and #entries > 0 then for i = 1, #entries do if entries[i].name and not entries[i].type then -- See https://github.com/luvit/luv/issues/660 local full_path = Path.concat { path, entries[i].name } log.trace("fs: fs_readdir falling back to fs_stat to find type", full_path) local stat = uv.fs_stat(full_path) entries[i].type = stat.type end all_entries[#all_entries + 1] = entries[i] end else log.trace("fs: fs_readdir exhausted scan", path) exhausted = true end until exhausted uv.fs_closedir(dir) return all_entries end ---@param path string ---@param new_path string function M.symlink(path, new_path) log.trace("fs: symlink", path, new_path) uv.fs_symlink(path, new_path) end ---@param path string ---@param mode integer function M.chmod(path, mode) log.trace("fs: chmod", path, mode) uv.fs_chmod(path, mode) end return M end return { async = make_module(require "mason-core.async.uv"), sync = make_module(vim.loop), }