From ec07bf9163f4c8c45e6409381bd75bab58b8d160 Mon Sep 17 00:00:00 2001 From: Tyler Miller Date: Mon, 29 May 2023 16:29:24 -0700 Subject: [PATCH] fix(compiler): broken `.git` dir path resolution Currently, in the file `lua/github-theme/init.lua`, the code `util.join_paths(debug.getinfo(1).source:sub(2, -23), '.git')` returns an absolute path ending in `**/lua/.git` which is not, and will never be, a valid path to the `.git` directory. This means that recompilation does not currently occur when the plugin updates or changes (unless user config changes too) and that users may miss crucial updates (e.g. bug fixes). 1. Fix bug by changing `util.join_paths(debug.getinfo(1).source:sub(2, -23), '.git')` to `debug.getinfo(1).source .. '/../../../.git'`, and then use luv's/libuv's `fs_stat()` to get the last modified time of this path. This change does not rely on any particular filenames existing in the path, but it still relies on a hard-coded depth. If the path does not exist or the stat is unsuccessful, force recompilation (as otherwise plugin updates could be missed by many users). 2. Use libuv/luv `fs_stat()` to get `.git` dir's mtime with nanosecond precision (NOTE: this function is only available by default in Neovim, not Vim, however, it appears that this plugin isn't compatible with Vim currently anyway, so this shouldn't be an issue). 3. Correctly handle `.git` files, as `.git` is not always a directory. See #262 --- lua/github-theme/init.lua | 68 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/lua/github-theme/init.lua b/lua/github-theme/init.lua index 978b6171..bf20a957 100644 --- a/lua/github-theme/init.lua +++ b/lua/github-theme/init.lua @@ -1,3 +1,4 @@ +local uv = vim.loop local config = require('github-theme.config') local function read_file(filepath) @@ -17,6 +18,16 @@ local function write_file(filepath, content) end end +local function stat_file(path) + for _ = 1, 3 do + local stat = uv.fs_stat(path) + if stat then + return stat + end + uv.sleep(1) + end +end + local M = {} function M.reset() @@ -94,11 +105,60 @@ M.setup = function(opts) local cached_path = util.join_paths(config.options.compile_path, 'cache') local cached = read_file(cached_path) - local git_path = util.join_paths(debug.getinfo(1).source:sub(2, -23), '.git') - local git = vim.fn.getftime(git_path) - local hash = require('github-theme.lib.hash')(opts) .. (git == -1 and git_path or git) + local git_mtime + local git_path = debug.getinfo(1).source + + if (git_path or ''):find('^@.') then + git_path = git_path:sub(2) .. '/../../../.git' + local st = stat_file(git_path) + + if not st then + goto skip + end + + -- Handle a .git "file" (e.g. worktree or submodule) + if st.type == 'file' then + local f = io.open(git_path, 'r') + + if not f then + goto skip + end + + local gitdir_path = (f:read('*l') or ''):match('^gitdir: (.+)') + f:close() + + if not gitdir_path then + goto skip + end + + git_path = gitdir_path + st = stat_file(git_path) + + if not st then + goto skip + end + end + + local sec, nsec = st.mtime.sec, st.mtime.nsec or 0 + + if nsec == 1e9 then + sec = sec + 1 + nsec = 0 + end + + git_mtime = ('%d.%09d'):format(sec, nsec) + end + + ::skip:: + + local hash = ('%s %s'):format( + require('github-theme.lib.hash')(opts), + git_mtime or git_path + ) - if cached ~= hash then + -- Force re-compile if .git dir could not be detected (plugin may have been + -- updated and we don't want to use a stale cache). + if cached ~= hash or not git_mtime then M.compile() write_file(cached_path, hash) end