Skip to content

Commit 8756cd4

Browse files
committed
feat: better handling of server installation path
The plugin should not assume its folder is writable. Instead, try to search for a writable folder by checking the data folder and the runtime paths. Also allows the user to give the path to the server's executable intead of always compiling it. All of this makes the plugin friendlier to restricted/read-only environments, like nix.
1 parent 3d2828a commit 8756cd4

7 files changed

Lines changed: 156 additions & 16 deletions

File tree

doc/gitlab.nvim.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,10 @@ Here is the default setup function. All of these values are optional, and if
144144
you call this function with no values the defaults will be used:
145145
>lua
146146
require("gitlab").setup({
147-
port = nil, -- The port of the Go server, which runs in the background, if omitted or `nil` the port will be chosen automatically
147+
server = {
148+
binary = nil, -- The path to the server binary. If omitted or nil, the server will be built
149+
port = nil, -- The port of the Go server, which runs in the background. If omitted or `nil` the port will be chosen automatically
150+
},
148151
log_path = vim.fn.stdpath("cache") .. "/gitlab.nvim.log", -- Log path for the Go server
149152
config_path = nil, -- Custom path for `.gitlab.nvim` file, please read the "Connecting to Gitlab" section
150153
debug = {
@@ -678,7 +681,7 @@ by a |motion|.
678681
Either the operator or the motion can be preceded by a count, so that `3sj` is
679682
equivalent to `s3j`, and they both create a comment for the current line and
680683
three more lines downwards. Similarly, both `2s`|ap| and `s2`|ap| create a suggestion
681-
for two "outer" paragraphs.
684+
for two "outer" paragraphs.
682685

683686
The operators force |linewise| visual selection, so they work correctly even
684687
if the motion itself works |characterwise| (e.g., |i(| for selecting the inner

flake.lock

Lines changed: 61 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
inputs = {
3+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
4+
flake-utils.url = "github:numtide/flake-utils";
5+
};
6+
7+
outputs = { self, flake-utils, nixpkgs }:
8+
flake-utils.lib.eachDefaultSystem (system:
9+
let
10+
pkgs = import nixpkgs { inherit system; config.allowUnfree = true; };
11+
gitlab-nvim-server = pkgs.buildGoModule {
12+
pname = "gitlab.nvim-server";
13+
version = "git";
14+
src = ./.;
15+
vendorHash = "sha256-OLAKTdzqynBDHqWV5RzIpfc3xZDm6uYyLD4rxbh0DMg=";
16+
postInstall = ''
17+
cp -r ${./cmd/config} $out/bin/config
18+
mv $out/bin/cmd $out/bin/gitlab.nvim
19+
'';
20+
};
21+
gitlab-nvim = pkgs.vimUtils.buildVimPlugin {
22+
name = "gitlab.nvim";
23+
src = ./.;
24+
doCheck = false;
25+
};
26+
in
27+
rec {
28+
formatter = pkgs.nixpkgs-fmt;
29+
packages.gitlab-nvim-server = gitlab-nvim-server;
30+
packages.gitlab-nvim = gitlab-nvim;
31+
packages.default = packages.gitlab-nvim;
32+
}
33+
);
34+
}

lua/gitlab/init.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ local function setup(args)
4444
return
4545
end
4646

47-
server.build() -- Builds the Go binary if it doesn't exist
4847
state.merge_settings(args) -- Merges user settings with default settings
48+
server.build() -- Builds the Go binary if it doesn't exist
4949
state.set_global_keymaps() -- Sets keymaps that are not bound to a specific buffer
5050
require("gitlab.colors") -- Sets colors
5151
reviewer.init()

lua/gitlab/job.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ local M = {}
66

77
M.run_job = function(endpoint, method, body, callback)
88
local state = require("gitlab.state")
9-
local args = { "-s", "-X", (method or "POST"), string.format("localhost:%s", state.settings.port) .. endpoint }
9+
local args = { "-s", "-X", (method or "POST"), string.format("localhost:%s", state.settings.server.port) .. endpoint }
1010

1111
if body ~= nil then
1212
local encoded_body = vim.json.encode(body)

lua/gitlab/server.lua

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ end
3030

3131
-- Starts the Go server and call the callback provided
3232
M.start = function(callback)
33-
local port = tonumber(state.settings.port) or 0
33+
local port = tonumber(state.settings.server.port) or 0
3434
local parsed_port = nil
3535
local callback_called = false
3636

@@ -51,7 +51,7 @@ M.start = function(callback)
5151
settings = settings:gsub('"', '\\"')
5252
end
5353

54-
local command = string.format('"%s" "%s"', state.settings.bin, settings)
54+
local command = string.format('"%s" "%s"', state.settings.server.binary, settings)
5555

5656
local job_id = vim.fn.jobstart(command, {
5757
on_stdout = function(_, data)
@@ -61,7 +61,7 @@ M.start = function(callback)
6161
port = line:match("Server started on port:%s+(%d+)")
6262
if port ~= nil then
6363
parsed_port = port
64-
state.settings.port = port
64+
state.settings.server.port = port
6565
break
6666
end
6767
end
@@ -105,26 +105,59 @@ end
105105
-- Builds the Go binary with the current Git tag.
106106
M.build = function(override)
107107
local file_path = u.current_file_path()
108-
local parent_dir = vim.fn.fnamemodify(file_path, ":h:h:h:h")
108+
state.settings.root_path = vim.fn.fnamemodify(file_path, ":h:h:h:h")
109+
110+
-- If the user provided a path to the server, don't build it.
111+
if state.settings.server.binary ~= nil then
112+
local binary_exists = vim.loop.fs_stat(state.settings.server.binary)
113+
if binary_exists == nil then
114+
u.notify(
115+
string.format("The user-provided server path (%s) does not exist.", state.settings.server.binary),
116+
vim.log.levels.ERROR
117+
)
118+
end
119+
return
120+
end
121+
122+
-- If the user did not provide a path, we build it and place it in either the data path, or the
123+
-- first writable path we find in the runtime.
124+
local datapath = vim.fn.stdpath("data")
125+
local runtimepath = vim.api.nvim_list_runtime_paths()
126+
table.insert(runtimepath, 1, datapath)
127+
128+
local bin_folder
129+
for _, path in ipairs(runtimepath) do
130+
local ok, err = vim.loop.fs_access(path, "w")
131+
if err == nil and ok ~= nil and ok then
132+
bin_folder = path .. u.path_separator .. "gitlab.nvim" .. u.path_separator .. "bin"
133+
if vim.fn.mkdir(bin_folder, "p") == 1 then
134+
state.settings.server.binary = bin_folder .. u.path_separator .. "server"
135+
break
136+
end
137+
end
138+
end
109139

110-
local bin_name = u.is_windows() and "bin.exe" or "bin"
111-
state.settings.root_path = parent_dir
112-
state.settings.bin = parent_dir .. u.path_separator .. "cmd" .. u.path_separator .. bin_name
140+
if state.settings.server.binary == nil then
141+
u.notify("Could not find a writable folder in the runtime path to save the server to.", vim.log.levels.ERROR)
142+
return
143+
end
113144

114145
if not override then
115-
local binary_exists = vim.loop.fs_stat(state.settings.bin)
146+
local binary_exists = vim.loop.fs_stat(state.settings.server.binary)
116147
if binary_exists ~= nil then
117148
return
118149
end
119150
end
120151

121-
local version_output = vim.system({ "git", "describe", "--tags", "--always" }, { cwd = parent_dir }):wait()
152+
local version_output = vim
153+
.system({ "git", "describe", "--tags", "--always" }, { cwd = state.settings.root_path })
154+
:wait()
122155
local version = version_output.code == 0 and vim.trim(version_output.stdout) or "unknown"
123156

124157
local ldflags = string.format("-X main.Version=%s", version)
125158
local res = vim
126159
.system(
127-
{ "go", "build", "-ldflags", ldflags, "-o", bin_name },
160+
{ "go", "build", "-buildvcs=false", "-ldflags", ldflags, "-o", state.settings.server.binary },
128161
{ cwd = state.settings.root_path .. u.path_separator .. "cmd" }
129162
)
130163
:wait()
@@ -133,6 +166,12 @@ M.build = function(override)
133166
u.notify(string.format("Failed to install with status code %d:\n%s", res.code, res.stderr), vim.log.levels.ERROR)
134167
return false
135168
end
169+
170+
local Path = require("plenary.path")
171+
local src = Path:new(state.settings.root_path .. u.path_separator .. "cmd" .. u.path_separator .. "config")
172+
local dest = Path:new(bin_folder .. u.path_separator .. "config")
173+
src:copy({ destination = dest, recursive = true, override = true })
174+
136175
u.notify("Installed successfully!", vim.log.levels.INFO)
137176
return true
138177
end
@@ -185,7 +224,7 @@ M.get_version = function(callback)
185224
local version_output = vim.system({ "git", "describe", "--tags", "--always" }, { cwd = parent_dir }):wait()
186225
local plugin_version = version_output.code == 0 and vim.trim(version_output.stdout) or "unknown"
187226

188-
local args = { "-s", "-X", "GET", string.format("localhost:%s/version", state.settings.port) }
227+
local args = { "-s", "-X", "GET", string.format("localhost:%s/version", state.settings.server.port) }
189228

190229
-- We call the "/version" endpoint here instead of through the regular jobs pattern because earlier versions of the plugin
191230
-- may not have it. We handle a 404 as an "unknown" version error.

lua/gitlab/state.lua

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ end
4545
M.settings = {
4646
auth_provider = M.default_auth_provider,
4747
file_separator = u.path_separator,
48-
port = nil, -- choose random port
48+
server = {
49+
binary = nil, -- path to the server binary. if nil, it will be compiled, otherwise the existing binary at this path will be used
50+
port = nil, -- choose random port
51+
},
4952
debug = {
5053
request = false,
5154
response = false,

0 commit comments

Comments
 (0)