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
149
150
151
152
153
154
155
|
local platform = require "nvim-lsp-installer.platform"
local log = require "nvim-lsp-installer.log"
local Data = require "nvim-lsp-installer.data"
local M = {}
---@alias ServerInstallCallback fun(success: boolean)
---@class ServerInstallContext
---@field requested_server_version string|nil @The version requested by the user.
---@field stdio_sink StdioSink
---@field github_release_file string|nil @Only available if context.use_github_release_file has been called.
---@alias ServerInstallerFunction fun(server: Server, callback: ServerInstallCallback, context: ServerInstallContext)
--- Composes multiple installer functions into one.
---@param installers ServerInstallerFunction[]
---@return ServerInstallerFunction
function M.pipe(installers)
if #installers == 0 then
error "No installers to pipe."
end
return function(server, callback, context)
local function execute(idx)
local ok, err = pcall(installers[idx], server, function(success)
if not success then
-- oh no, error. exit early
callback(success)
elseif installers[idx + 1] then
-- iterate
execute(idx + 1)
else
-- we done
callback(success)
end
end, context)
if not ok then
context.stdio_sink.stderr(tostring(err) .. "\n")
callback(false)
end
end
execute(1)
end
end
--- Composes multiple installer function into one - in reversed order.
---@param installers ServerInstallerFunction[]
function M.compose(installers)
return M.pipe(Data.list_reverse(installers))
end
---@param installers ServerInstallerFunction[]
---@return ServerInstallerFunction @An installer function that will serially execute the provided installers, until the first one succeeds.
function M.first_successful(installers)
if #installers == 0 then
error "No installers to pipe."
end
return function(server, callback, context)
local function execute(idx)
log.fmt_trace("Executing installer idx=%d", idx)
local ok, err = pcall(installers[idx], server, function(success)
log.fmt_trace("Installer idx=%d on exit with success=%s", idx, success)
if not success and installers[idx + 1] then
-- iterate
execute(idx + 1)
else
callback(success)
end
end, context)
if not ok then
context.stdio_sink.stderr(tostring(err) .. "\n")
if installers[idx + 1] then
execute(idx + 1)
else
callback(false)
end
end
end
execute(1)
end
end
--- Wraps the provided server installer to always succeeds.
---@param installer ServerInstallerFunction
---@return ServerInstallerFunction
function M.always_succeed(installer)
return function(server, callback, context)
installer(server, function()
callback(true)
end, context)
end
end
---@param platform_table table<Platform, ServerInstallerFunction>
---@return ServerInstallerFunction | nil
local function get_by_platform(platform_table)
if platform.is_mac then
return platform_table.mac or platform_table.unix
elseif platform.is_linux then
return platform_table.linux or platform_table.unix
elseif platform.is_unix then
return platform_table.unix
elseif platform.is_win then
return platform_table.win
else
return nil
end
end
--- Creates a server installer that executes the given installer for the current platform.
--- If there is no server installer provided for the current platform, the installer will instantly exit successfully.
---@param platform_table table<Platform, ServerInstallerFunction>
---@return ServerInstallerFunction
function M.on(platform_table)
return function(server, callback, context)
local installer = get_by_platform(platform_table)
if installer then
if type(installer) == "function" then
installer(server, callback, context)
else
M.pipe(installer)(server, callback, context)
end
else
callback(true)
end
end
end
--- Creates a server installer that executes the given installer for the current platform.
--- If there is no server installer provided for the current platform, the installer will instantly exit with a failure.
---@param platform_table table<Platform, ServerInstallerFunction>
---@return ServerInstallerFunction
function M.when(platform_table)
return function(server, callback, context)
local installer = get_by_platform(platform_table)
if installer then
if type(installer) == "function" then
installer(server, callback, context)
else
M.pipe(installer)(server, callback, context)
end
else
context.stdio_sink.stderr(
("Current operating system is not yet supported for server %q.\n"):format(server.name)
)
callback(false)
end
end
end
return M
|