aboutsummaryrefslogtreecommitdiffstats
path: root/lua/nvim-lsp-installer/fs.lua
blob: 3725f15418a589dce7a1e1c287c79d63f01f7177 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
local pathm = require "nvim-lsp-installer.path"
local log = require "nvim-lsp-installer.log"
local settings = require "nvim-lsp-installer.settings"

local uv = vim.loop
local M = {}

local function assert_ownership(path)
    if not pathm.is_subdirectory(settings.current.install_root_dir, path) then
        log.fmt_error("assert_ownership() failed on path %s", path)
        error(
            ("Refusing to operate on path (%s) outside of the servers root dir (%s)."):format(
                path,
                settings.current.install_root_dir
            )
        )
    end
end

---@param path string @The full path to the file/dir to recursively delete. Will refuse to operate on paths outside of the install_root dir setting.
function M.rmrf(path)
    log.debug("fs: rmrf", path)
    assert_ownership(path)
    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 @The full path to the file/dir to rename. Will refuse to operate on paths outside of the install_root dir setting.
---@param new_path string @The full path to the new file/dir name. Will refuse to operate on paths outside of the install_root dir setting.
function M.rename(path, new_path)
    log.debug("fs: rename", path, new_path)
    assert_ownership(path)
    assert_ownership(new_path)
    assert(uv.fs_rename(path, new_path))
end

---@param path string @The full path to the directory to create. Will refuse to operate on paths outside of the install_root dir setting.
function M.mkdirp(path)
    log.debug("fs: mkdirp", path)
    assert_ownership(path)
    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 @The full path to the directory to create. Will refuse to operate on paths outside of the install_root dir setting.
function M.mkdir(path)
    log.debug("fs: mkdir", path)
    assert_ownership(path)
    assert(uv.fs_mkdir(path, 493)) -- 493(10) == 755(8)
end

---Recursively removes the path if it exists before creating a directory.
---@param path string @The full path to the directory to create. Will refuse to operate on paths outside of the install_root dir setting.
function M.rm_mkdirp(path)
    if M.dir_exists(path) then
        M.rmrf(path)
    end
    return M.mkdirp(path)
end

---@param path string @The full path to check if it 1) exists, and 2) is a directory.
---@return boolean
function M.dir_exists(path)
    local ok, stat = pcall(M.fstat, path)
    if not ok then
        return false
    end
    return stat.type == "directory"
end

---@param path string @The full path to check if it 1) exists, and 2) is a file.
---@return boolean
function M.file_exists(path)
    local ok, stat = pcall(M.fstat, path)
    if not ok then
        return false
    end
    return stat.type == "file"
end

---@param path string @The full path to the file to get the file status from.
---@return table @Returns a struct of type uv_fs_t.
function M.fstat(path)
    local fd = assert(uv.fs_open(path, "r", 438))
    local fstat = assert(uv.fs_fstat(fd))
    assert(uv.fs_close(fd))
    return fstat
end

---@param path string @The full path to the file to write.
---@param contents string @The contents to write.
function M.write_file(path, contents)
    log.fmt_debug("fs: write_file %s", path)
    assert_ownership(path)
    local fd = assert(uv.fs_open(path, "w", 438))
    uv.fs_write(fd, contents, -1)
    assert(uv.fs_close(fd))
end

---@param path string @The full path to the file to read.
function M.read_file(path)
    log.fmt_debug("fs: read_file %s", path)
    assert_ownership(path)
    local fd = assert(uv.fs_open(path, "r", 438))
    local fstat = assert(uv.fs_fstat(fd))
    local contents = assert(uv.fs_read(fd, fstat.size, 0))
    assert(uv.fs_close(fd))
    return contents
end

function M.append_file(path, contents)
    log.fmt_debug("fs: append_file %s", path)
    assert_ownership(path)
    local fd = assert(uv.fs_open(path, "a", 438))
    uv.fs_write(fd, contents, -1)
    assert(uv.fs_close(fd))
end

---@alias ReaddirEntry {name: string, type: string}

---@param path string @The full path to the directory to read.
---@return ReaddirEntry[]
function M.readdir(path)
    local dir = assert(uv.fs_opendir(path, nil, 25))
    local all_entries = {}
    local exhausted = false

    repeat
        local entries = uv.fs_readdir(dir)
        if entries and #entries > 0 then
            for i = 1, #entries do
                all_entries[#all_entries + 1] = entries[i]
            end
        else
            exhausted = true
        end
    until exhausted

    assert(uv.fs_closedir(dir))

    return all_entries
end

return M