@@ 159,17 159,60 @@ local pick_urls = function(hostname)
return config.urls_by_hostname[hostname]
end
-local function go_modcache_info(filename)
- local gocache = vim.fn.systemlist({ 'go', 'env', 'GOMODCACHE' })[1]
- if not gocache or filename:sub(1, #gocache) ~= gocache then
- return false
- end
-
- local trimmed = filename:sub(#gocache + 2) -- Remove the prefix (and /)
- local module = trimmed:match '^(.-@.-)/'
- local rel_filepath = trimmed:match '.-@.-/(.*)'
-
- local output = vim.fn.system { 'go', 'mod', 'download', '-json', module }
+local extract_module_version = function(path)
+ local cache = vim.fn.systemlist({ 'go', 'env', 'GOMODCACHE' })[1]
+ if not cache or path:sub(1, #cache) ~= cache then
+ error 'path not in cache'
+ end
+
+ local trimmed = path:sub(#cache + 2) -- Remove the prefix (and /)
+ local match, _, module, version = string.find(trimmed, '([^@]+)@([^/]+)')
+ if not match then
+ error 'not matched'
+ end
+ local rel_filepath = trimmed:match '.-@.-/(.*)' or ''
+ return module, version, rel_filepath
+end
+
+local extract_module_version_test = function()
+ local cache = vim.fn.systemlist({ 'go', 'env', 'GOMODCACHE' })[1]
+ local module, version, file
+
+ module, version, file = extract_module_version(cache .. '/github.com/google/uuid@v1.3.1')
+ assert(module == 'github.com/google/uuid')
+ assert(version == 'v1.3.1')
+ assert(file == '')
+
+ module, version, file = extract_module_version(cache .. '/github.com/google/uuid@v1.3.1/')
+ assert(module == 'github.com/google/uuid')
+ assert(version == 'v1.3.1')
+ assert(file == '')
+
+ module, version, file = extract_module_version(cache .. '/github.com/google/groupcache@v0.0.0-20210331224755-41bb18bfe9da/')
+ assert(module == 'github.com/google/groupcache')
+ assert(version == 'v0.0.0-20210331224755-41bb18bfe9da')
+ assert(file == '')
+
+ module, version, file =
+ extract_module_version(cache .. '/github.com/rancher/rancher/pkg/apis@v0.0.0-20211022200336-bd75b096ba9e/management.cattle.io/v3/zz_generated_deepcopy.go')
+ assert(module == 'github.com/rancher/rancher/pkg/apis')
+ assert(version == 'v0.0.0-20211022200336-bd75b096ba9e')
+ assert(file == 'management.cattle.io/v3/zz_generated_deepcopy.go')
+end
+
+--
+--
+-- "Origin": { -> Always present if using GOPROXY=direct
+-- "VCS": "git",
+-- "URL": "https://github.com/rancher/rancher",
+-- "Subdir": "pkg/apis", -> When it's a module NOT at the top level of the repo
+-- "Hash": "bd75b096ba9e9736c82faadd7f08a4c73f6cdd2a", -> The commit
+-- "Ref": "/refs/tags/v0.1.2" -> not always there
+-- }
+--
+--
+local function go_modcache_info(module, version, rel_filepath)
+ local output = vim.fn.system { 'go', 'mod', 'download', '-json', string.format('%s@%s', module, version) }
if output == '' then
return false
end
@@ 182,6 225,7 @@ local function go_modcache_info(filename)
if not json.Origin then
-- XXX: This will be super slow in most cases. Need to find a better way and
-- potentially make everything async..
+ vim.notify('Fallback to slow gomod download', vim.log.levels.WARN)
output = vim.fn.system { 'env', 'GOPROXY=direct', 'GOMODCACHE=' .. fallback_gocache_dir, 'go', 'mod', 'download', '-json', module }
if output == '' then
return false
@@ 205,6 249,12 @@ local function go_modcache_info(filename)
end
end
+ if json.Origin.Subdir ~= nil then
+ -- rel_filepath is always relative to the module, so if the module is not
+ -- at the root of the repository, we must append the Subdir to it
+ rel_filepath = string.format('%s/%s', json.Origin.Subdir, rel_filepath)
+ end
+
local hostname = json.Origin.URL:match '://([^/]+)/'
return {
commit = commit,
@@ 351,17 401,20 @@ local get_repo_info = function()
line2 = vim.fn.getpos('.')[2]
end
- local gomodcache = go_modcache_info(filename)
- if gomodcache then
- local hostname = gomodcache.hostname
- local info = {
- base_url = gomodcache.remote_url,
- ref = gomodcache.commit,
- filepath = gomodcache.rel_filepath,
- line1 = line1 or nil,
- line2 = line2 or nil,
- }
- return { hostname = hostname, info = info }
+ local ok, module, version, filepath_in_module = pcall(extract_module_version, filename)
+ if ok then
+ local gomodcache = go_modcache_info(module, version, filepath_in_module)
+ if gomodcache then
+ local hostname = gomodcache.hostname
+ local info = {
+ base_url = gomodcache.remote_url,
+ ref = gomodcache.commit,
+ filepath = gomodcache.rel_filepath,
+ line1 = line1 or nil,
+ line2 = line2 or nil,
+ }
+ return { hostname = hostname, info = info }
+ end
end
local project_dir = M.find_git_project_root(vim.fn.fnamemodify(filename, ':h'))
@@ 532,66 585,64 @@ M.open_tree_url = function()
open_url(url)
end
-local get_gomod_repo_and_version = function(mline)
+local get_gomod_module_version = function(mline)
local line = mline or vim.fn.getline '.'
- local match, repo, version
+ local match, module, version
-- Matches
-- k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20230215170314-b923b89432b0
- match, _, repo, version = string.find(line, '^ [^ ]+ => ([^ ]+) ([^ ]+)')
+ match, _, module, version = string.find(line, '^ [^ ]+ => ([^ ]+) ([^ ]+)')
if match then
- return repo, version
+ return module, version
end
-- Matches
-- k8s.io/apimachinery v1.1.1 => k8s.io/apimachinery v0.0.0-20230215170314-b923b89432b0
- match, _, repo, version = string.find(line, '^ [^ ]+ [^ ]+ => ([^ ]+) ([^ ]+)')
+ match, _, module, version = string.find(line, '^ [^ ]+ [^ ]+ => ([^ ]+) ([^ ]+)')
if match then
- return repo, version
+ return module, version
end
-- Matches
-- replace k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20230215170314-b923b89432b0
- match, _, repo, version = string.find(line, '^replace [^ ]+ => ([^ ]+) ([^ ]+)')
+ match, _, module, version = string.find(line, '^replace [^ ]+ => ([^ ]+) ([^ ]+)')
if match then
- return repo, version
+ return module, version
end
-- Matches
-- replace k8s.io/apimachinery v1.1.1 => k8s.io/apimachinery v0.0.0-20230215170314-b923b89432b0
- match, _, repo, version = string.find(line, '^replace [^ ]+ [^ ]+ => ([^ ]+) ([^ ]+)')
+ match, _, module, version = string.find(line, '^replace [^ ]+ [^ ]+ => ([^ ]+) ([^ ]+)')
if match then
- return repo, version
+ return module, version
end
-- Matches
-- k8s.io/apimachinery v3.0.1
-- k8s.io/apimachinery v1.1.1 // indirect
- match, _, repo, version = string.find(line, '^ ([^ ]+) ([^ ]+)')
+ match, _, module, version = string.find(line, '^ ([^ ]+) ([^ ]+)')
if match then
- return repo, version
+ return module, version
end
-- Matches
-- require k8s.io/apimachinery v3.0.1
-- require k8s.io/apimachinery v1.1.1 // indirect
- match, _, repo, version = string.find(line, '^require ([^ ]+) ([^ ]+)')
+ match, _, module, version = string.find(line, '^require ([^ ]+) ([^ ]+)')
if match then
- return repo, version
+ return module, version
end
return nil, nil
end
M.get_gomod_tree_url = function()
- local repo, version = get_gomod_repo_and_version()
- if not repo then
+ local module, version = get_gomod_module_version()
+ if not module then
error 'unsupported go.mod directive'
end
- local gocache = vim.fn.systemlist({ 'go', 'env', 'GOMODCACHE' })[1]
- local dir = string.format('%s/%s@%s/', gocache, repo, version)
- local gomodcache = go_modcache_info(dir)
+ local gomodcache = go_modcache_info(module, version, nil)
if gomodcache then
local hostname = gomodcache.hostname
local info = {
@@ 629,27 680,25 @@ end
local get_gosum_repo_and_version = function()
local line = vim.fn.getline '.'
- local match, repo, version
+ local match, module, version
-- Matches
-- cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
- match, _, repo, version = string.find(line, '^([^ ]+) ([^ /]+)')
+ match, _, module, version = string.find(line, '^([^ ]+) ([^ /]+)')
if match then
- return repo, version
+ return module, version
end
return nil, nil
end
M.get_gosum_tree_url = function()
- local repo, version = get_gosum_repo_and_version()
- if not repo then
+ local module, version = get_gosum_repo_and_version()
+ if not module then
error 'unsupported go.sum directive'
end
- local gocache = vim.fn.systemlist({ 'go', 'env', 'GOMODCACHE' })[1]
- local dir = string.format('%s/%s@%s/', gocache, repo, version)
- local gomodcache = go_modcache_info(dir)
+ local gomodcache = go_modcache_info(module, version)
if gomodcache then
local hostname = gomodcache.hostname
local info = {
@@ 688,19 737,19 @@ end
local get_gomod_repo_and_version_test = function()
local repo, version
- repo, version = get_gomod_repo_and_version ' k8s.io/api v0.27.4'
+ repo, version = get_gomod_module_version ' k8s.io/api v0.27.4'
assert(repo == 'k8s.io/api')
assert(version == 'v0.27.4')
- repo, version = get_gomod_repo_and_version 'require k8s.io/api v0.27.4'
+ repo, version = get_gomod_module_version 'require k8s.io/api v0.27.4'
assert(repo == 'k8s.io/api')
assert(version == 'v0.27.4')
- repo, version = get_gomod_repo_and_version ' k8s.io/api => k8s.io/api v0.27.4'
+ repo, version = get_gomod_module_version ' k8s.io/api => k8s.io/api v0.27.4'
assert(repo == 'k8s.io/api')
assert(version == 'v0.27.4')
- repo, version = get_gomod_repo_and_version ' k8s.io/api v0.26.3 => k8s.io/api v0.27.4'
+ repo, version = get_gomod_module_version ' k8s.io/api v0.26.3 => k8s.io/api v0.27.4'
assert(repo == 'k8s.io/api')
assert(version == 'v0.27.4')
end
@@ 712,7 761,9 @@ M.setup = function(uconfig)
vim.fn.mkdir(fallback_gocache_dir, 'p')
-- XXX: Need to learn how to run unit test with neotest instead of here..
+ extract_module_version_test()
get_gomod_repo_and_version_test()
+
vim.validate { config = { uconfig, 'table', true } }
config = vim.tbl_deep_extend('force', config, uconfig)