Skip to content

Commit 18ce09e

Browse files
authored
perf(build): improve git submodules installation speed (#50)
1 parent 69e2d38 commit 18ce09e

File tree

2 files changed

+131
-42
lines changed

2 files changed

+131
-42
lines changed

README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ And multiple trigger timings (colorschemes don't have end time):
7070
1. Don't lazy this plugin, it only takes ~4 ms to load.
7171
2. Load this plugin before all other start plugins.
7272

73-
**Warning:** hold your wifi, it `clone` and `pull` a lot of git repos!
74-
7573
### [lazy.nvim](https://github.com/folke/lazy.nvim)
7674

7775
```lua
@@ -98,6 +96,15 @@ require('pckr').add({
9896
})
9997
```
10098

99+
If you have issues on running multiple git clone/pull commands, try set `concurrency=1` in the `update` API:
100+
101+
```lua
102+
require('colorbox').update({
103+
--- @type integer
104+
concurrency = 4,
105+
})
106+
```
107+
101108
## 🔧 Configuration
102109

103110
```lua
@@ -128,9 +135,9 @@ require('colorbox').setup({
128135
--- @type "dark"|"light"|nil
129136
background = nil,
130137

131-
-- cache dir
132-
-- for macos/linux: $HOME/.local/share/nvim/colorbox.nvim
133-
-- for windows: $env:USERPROFILE\AppData\Local\nvim-data\colorbox.nvim
138+
-- Cache directory
139+
-- * For macos/linux: $HOME/.local/share/nvim/colorbox.nvim
140+
-- * For windows: $env:USERPROFILE\AppData\Local\nvim-data\colorbox.nvim
134141
--
135142
--- @type string
136143
cache_dir = string.format("%s/colorbox.nvim", vim.fn.stdpath('data')),

lua/colorbox.lua

Lines changed: 119 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ end
191191

192192
local function _policy()
193193
if Configs.background == "dark" or Configs.background == "light" then
194-
vim.cmd(string.format([[set background=%s]], Configs.background))
194+
vim.opt.background = Configs.background
195195
end
196196
if Configs.policy == "shuffle" then
197197
_policy_shuffle()
@@ -263,7 +263,13 @@ local function setup(opts)
263263
_timing()
264264
end
265265

266-
local function update()
266+
--- @param opts {concurrency:integer}?
267+
local function update(opts)
268+
opts = opts or { concurrency = 4 }
269+
opts.concurrency = type(opts.concurrency) == "number"
270+
and math.max(opts.concurrency, 1)
271+
or 4
272+
267273
logger.setup({
268274
name = "colorbox",
269275
level = LogLevels.DEBUG,
@@ -282,22 +288,42 @@ local function update()
282288
)
283289
vim.opt.packpath:append(home_dir)
284290

285-
local jobs = {}
286291
local HandleToColorSpecsMap =
287292
require("colorbox.db").get_handle_to_color_specs_map()
293+
294+
-- a list of job params
295+
--- @type colorbox.Options[]
296+
local jobs_pending_queue = {}
297+
298+
-- a list of job id
299+
--- @type integer[]
300+
local jobs_working_queue = {}
301+
302+
-- job id to job params map
303+
--- @type table<integer, colorbox.Options>
304+
local jobid_to_jobs_map = {}
305+
306+
local prepared_count = 0
307+
local finished_count = 0
308+
309+
for handle, spec in pairs(HandleToColorSpecsMap) do
310+
prepared_count = prepared_count + 1
311+
end
312+
logger.info("started %s jobs", vim.inspect(prepared_count))
313+
288314
for handle, spec in pairs(HandleToColorSpecsMap) do
289315
local function _on_output(chanid, data, name)
290316
if type(data) == "table" then
291317
logger.debug(
292-
"%s (%s): %s",
293-
vim.inspect(handle),
318+
"(%s) %s: %s",
294319
vim.inspect(name),
320+
vim.inspect(handle),
295321
vim.inspect(data)
296322
)
297323
local lines = {}
298-
for _, line in ipairs(data) do
299-
if string.len(vim.trim(line)) > 0 then
300-
table.insert(lines, line)
324+
for _, d in ipairs(data) do
325+
if type(d) == "string" and string.len(vim.trim(d)) > 0 then
326+
table.insert(lines, d)
301327
end
302328
end
303329
if #lines > 0 then
@@ -307,47 +333,103 @@ local function update()
307333
end
308334
local function _on_exit(jid, exitcode, name)
309335
logger.debug(
310-
"%s (%s-%s): exit with %s",
311-
vim.inspect(handle),
312-
vim.inspect(jid),
336+
"(%s-%s) %s: exit with %s",
313337
vim.inspect(name),
338+
vim.inspect(jid),
339+
vim.inspect(handle),
314340
vim.inspect(exitcode)
315341
)
342+
343+
local removed_from_working_queue = false
344+
for i, working_jobid in ipairs(jobs_working_queue) do
345+
if working_jobid == jid then
346+
table.remove(jobs_working_queue, i)
347+
removed_from_working_queue = true
348+
break
349+
end
350+
end
351+
if not removed_from_working_queue then
352+
logger.err(
353+
"failed to remove job id %s from jobs_working_queue: %s",
354+
vim.inspect(jid),
355+
vim.inspect(jobs_working_queue)
356+
)
357+
end
358+
if jobid_to_jobs_map[jid] == nil then
359+
logger.err(
360+
"failed to remove job id %s from jobid_to_jobs_map: %s",
361+
vim.inspect(jid),
362+
vim.inspect(jobid_to_jobs_map)
363+
)
364+
end
365+
jobid_to_jobs_map[jid] = nil
366+
367+
if #jobs_pending_queue > 0 then
368+
local waiting_job_param = jobs_pending_queue[1]
369+
table.remove(jobs_pending_queue, 1)
370+
371+
local new_jobid = vim.fn.jobstart(
372+
waiting_job_param.cmd,
373+
waiting_job_param.opts
374+
)
375+
table.insert(jobs_working_queue, new_jobid)
376+
jobid_to_jobs_map[new_jobid] = waiting_job_param
377+
378+
finished_count = finished_count + 1
379+
else
380+
logger.info("finished %s jobs", vim.inspect(finished_count))
381+
logger.close_file_mode_w()
382+
end
316383
end
317384

385+
local param = nil
318386
if
319387
vim.fn.isdirectory(spec.full_pack_path) > 0
320388
and vim.fn.isdirectory(spec.full_pack_path .. "/.git") > 0
321389
then
322-
local cmd = { "git", "pull" }
323-
logger.debug("update command:%s", vim.inspect(cmd))
324-
local jobid = vim.fn.jobstart(cmd, {
325-
cwd = spec.full_pack_path,
326-
stdout_buffered = true,
327-
stderr_buffered = true,
328-
on_stdout = _on_output,
329-
on_stderr = _on_output,
330-
on_exit = _on_exit,
331-
})
332-
table.insert(jobs, jobid)
390+
param = {
391+
handle = handle,
392+
cmd = { "git", "pull" },
393+
opts = {
394+
cwd = spec.full_pack_path,
395+
detach = true,
396+
stdout_buffered = true,
397+
stderr_buffered = true,
398+
on_stdout = _on_output,
399+
on_stderr = _on_output,
400+
on_exit = _on_exit,
401+
},
402+
}
333403
else
334-
local cmd =
335-
{ "git", "clone", "--depth=1", spec.url, spec.pack_path }
336-
logger.debug("install command:%s", vim.inspect(cmd))
337-
local jobid = vim.fn.jobstart(cmd, {
338-
cwd = home_dir,
339-
stdout_buffered = true,
340-
stderr_buffered = true,
341-
on_stdout = _on_output,
342-
on_stderr = _on_output,
343-
on_exit = _on_exit,
344-
})
345-
logger.debug("installing %s", vim.inspect(handle))
346-
table.insert(jobs, jobid)
404+
param = {
405+
handle = handle,
406+
cmd = { "git", "clone", "--depth=1", spec.url, spec.pack_path },
407+
opts = {
408+
cwd = home_dir,
409+
detach = true,
410+
stdout_buffered = true,
411+
stderr_buffered = true,
412+
on_stdout = _on_output,
413+
on_stderr = _on_output,
414+
on_exit = _on_exit,
415+
},
416+
}
417+
end
418+
419+
table.insert(jobs_pending_queue, param)
420+
421+
if #jobs_working_queue < opts.concurrency then
422+
local waiting_job_param = jobs_pending_queue[1]
423+
table.remove(jobs_pending_queue, 1)
424+
425+
local new_jobid =
426+
vim.fn.jobstart(waiting_job_param.cmd, waiting_job_param.opts)
427+
table.insert(jobs_working_queue, new_jobid)
428+
jobid_to_jobs_map[new_jobid] = waiting_job_param
429+
430+
finished_count = finished_count + 1
347431
end
348432
end
349-
vim.fn.jobwait(jobs)
350-
logger.close_file_mode_w()
351433
end
352434

353435
local M = { setup = setup, update = update }

0 commit comments

Comments
 (0)