Support $GO111MODULE with Go tooling

Allows the user to override $GO111MODULE environment variable through
ale options. This gives control over the default behavior of Go module
resolution.

Golang documentation:
https://github.com/golang/go/wiki/Modules#how-to-use-modules

Add `ale#Go#EnvString()` function to make it easy to add similar Go
environment variables in the future.

Use the new `EnvString` function in all available Go tools callbacks
& update tests

Also add test of linter command callback for `gofmt`
This commit is contained in:
Elias Martinez Cohen 2019-04-10 22:25:06 -04:00
parent 89f7292138
commit 49db8210f6
32 changed files with 269 additions and 15 deletions

View File

@ -5,11 +5,13 @@ call ale#Set('go_bingo_executable', 'bingo')
call ale#Set('go_bingo_options', '--mode stdio')
function! ale_linters#go#bingo#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'go_bingo_options'))
return ale#go#EnvString(a:buffer) . '%e' . ale#Pad(ale#Var(a:buffer, 'go_bingo_options'))
endfunction
function! ale_linters#go#bingo#FindProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'go.mod')
let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off'
let l:project_root = l:go_modules_off ?
\ '' : ale#path#FindNearestFile(a:buffer, 'go.mod')
let l:mods = ':h'
if empty(l:project_root)

View File

@ -11,6 +11,7 @@ function! ale_linters#go#gobuild#GetCommand(buffer) abort
" Run go test in local directory with relative path
return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . ale#Var(a:buffer, 'go_go_executable') . ' test'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' -c -o /dev/null ./'

View File

@ -1,10 +1,16 @@
" Author: neersighted <bjorn@neersighted.com>
" Description: gofmt for Go files
function! ale_linters#go#gofmt#GetCommand(buffer) abort
return ale#go#EnvString(a:buffer)
\ . '%e -e %t'
endfunction
call ale#linter#Define('go', {
\ 'name': 'gofmt',
\ 'output_stream': 'stderr',
\ 'executable': 'gofmt',
\ 'command': 'gofmt -e %t',
\ 'command': function('ale_linters#go#gofmt#GetCommand'),
\ 'callback': 'ale#handlers#unix#HandleAsError',
\})

View File

@ -10,13 +10,16 @@ function! ale_linters#go#golangci_lint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_golangci_lint_options')
let l:lint_package = ale#Var(a:buffer, 'go_golangci_lint_package')
if l:lint_package
return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e run '
\ . l:options
endif
return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e run '
\ . ale#Escape(l:filename)
\ . ' ' . l:options

View File

@ -7,7 +7,7 @@ call ale#Set('go_golint_options', '')
function! ale_linters#go#golint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_golint_options')
return '%e'
return ale#go#EnvString(a:buffer) . '%e'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' %t'
endfunction

View File

@ -14,11 +14,13 @@ function! ale_linters#go#gometalinter#GetCommand(buffer) abort
" be calculated to absolute paths in the Handler
if l:lint_package
return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e'
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endif
return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e'
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(l:filename))
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'

View File

@ -6,11 +6,15 @@ call ale#Set('go_gopls_executable', 'gopls')
call ale#Set('go_gopls_options', '--mode stdio')
function! ale_linters#go#gopls#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'go_gopls_options'))
return ale#go#EnvString(a:buffer)
\ . '%e'
\ . ale#Pad(ale#Var(a:buffer, 'go_gopls_options'))
endfunction
function! ale_linters#go#gopls#FindProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'go.mod')
let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off'
let l:project_root = l:go_modules_off ?
\ '' : ale#path#FindNearestFile(a:buffer, 'go.mod')
let l:mods = ':h'
if empty(l:project_root)

View File

@ -2,7 +2,8 @@
" Description: gosimple for Go files
function! ale_linters#go#gosimple#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer) . ' gosimple .'
return ale#path#BufferCdString(a:buffer) . ' '
\ . ale#go#EnvString(a:buffer) . 'gosimple .'
endfunction
call ale#linter#Define('go', {

View File

@ -6,7 +6,8 @@ function! ale_linters#go#gotype#GetCommand(buffer) abort
return ''
endif
return ale#path#BufferCdString(a:buffer) . ' gotype -e .'
return ale#path#BufferCdString(a:buffer) . ' '
\ . ale#go#EnvString(a:buffer) . 'gotype -e .'
endfunction
call ale#linter#Define('go', {

View File

@ -11,6 +11,7 @@ function! ale_linters#go#govet#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_govet_options')
return ale#path#BufferCdString(a:buffer) . ' '
\ . ale#go#EnvString(a:buffer)
\ . ale#Var(a:buffer, 'go_go_executable') . ' vet '
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' .'

View File

@ -15,8 +15,9 @@ function! ale_linters#go#langserver#GetCommand(buffer) abort
endif
let l:options = uniq(sort(l:options))
let l:env = ale#go#EnvString(a:buffer)
return join(extend(l:executable, l:options), ' ')
return l:env . join(extend(l:executable, l:options), ' ')
endfunction
call ale#linter#Define('go', {

View File

@ -8,17 +8,18 @@ function! ale_linters#go#staticcheck#GetCommand(buffer) abort
let l:filename = expand('#' . a:buffer . ':t')
let l:options = ale#Var(a:buffer, 'go_staticcheck_options')
let l:lint_package = ale#Var(a:buffer, 'go_staticcheck_lint_package')
let l:env = ale#go#EnvString(a:buffer)
" BufferCdString is used so that we can be sure the paths output from
" staticcheck can be calculated to absolute paths in the Handler
if l:lint_package
return ale#path#BufferCdString(a:buffer)
\ . 'staticcheck'
\ . l:env . 'staticcheck'
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endif
return ale#path#BufferCdString(a:buffer)
\ . 'staticcheck'
\ . l:env . 'staticcheck'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' ' . ale#Escape(l:filename)
endfunction

View File

@ -7,9 +7,10 @@ call ale#Set('go_gofmt_options', '')
function! ale#fixers#gofmt#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'go_gofmt_executable')
let l:options = ale#Var(a:buffer, 'go_gofmt_options')
let l:env = ale#go#EnvString(a:buffer)
return {
\ 'command': ale#Escape(l:executable)
\ 'command': l:env . ale#Escape(l:executable)
\ . ' -l -w'
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t',

View File

@ -7,13 +7,14 @@ call ale#Set('go_goimports_options', '')
function! ale#fixers#goimports#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'go_goimports_executable')
let l:options = ale#Var(a:buffer, 'go_goimports_options')
let l:env = ale#go#EnvString(a:buffer)
if !executable(l:executable)
return 0
endif
return {
\ 'command': ale#Escape(l:executable)
\ 'command': l:env . ale#Escape(l:executable)
\ . ' -l -w -srcdir %s'
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t',

View File

@ -2,9 +2,10 @@ call ale#Set('go_go_executable', 'go')
function! ale#fixers#gomod#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'go_go_executable')
let l:env = ale#go#EnvString(a:buffer)
return {
\ 'command': ale#Escape(l:executable) . ' mod edit -fmt %t',
\ 'command': l:env . ale#Escape(l:executable) . ' mod edit -fmt %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -25,3 +25,20 @@ function! ale#go#FindProjectRoot(buffer) abort
return ''
endfunction
call ale#Set('go_go111module', '')
" Return a string setting Go-specific environment variables
function! ale#go#EnvString(buffer) abort
let l:env = ''
" GO111MODULE - turn go modules behavior on/off
let l:go111module = ale#Var(a:buffer, 'go_go111module')
if !empty(l:go111module)
let l:env = ale#Env('GO111MODULE', l:go111module) . l:env
endif
return l:env
endfunction

View File

@ -29,6 +29,15 @@ g:ale_go_go_executable *g:ale_go_go_options*
The executable that will be run for the `gobuild` and `govet` linters, and
the `gomod` fixer.
g:ale_go_go111module *g:ale_go_go111module*
*b:ale_go_go111module*
Type: |String|
Default: `''`
Override the value of the `$GO111MODULE` environment variable for
golang tools.
===============================================================================
bingo *ale-go-bingo*

View File

@ -9,6 +9,7 @@ After:
endif
unlet! b:ale_completion_enabled
unlet! b:ale_go_go111module
call ale#assert#TearDownLinterTest()
@ -34,6 +35,14 @@ Execute(should set bingo options):
AssertLinter 'bingo',
\ ale#Escape('bingo') . ' --mode stdio --trace'
Execute(should support Go environment variables):
call ale#test#SetFilename('go_paths/go1/prj1/file.go')
let b:ale_go_go111module = 'on'
AssertLinter 'bingo',
\ ale#Env('GO111MODULE', 'on') . ale#Escape('bingo') . ' --mode stdio'
Execute(Should return directory for 'go.mod' if found in parent directory):
call ale#test#SetFilename('../go_files/test.go')
@ -44,3 +53,20 @@ Execute(Should return nearest directory with '.git' if found in parent directory
call mkdir(g:dir . '/.git')
AssertLSPProject g:dir
Execute(Should ignore 'go.mod' and return '.git' dir if modules off):
call ale#test#SetFilename('../go_files/test.go')
let b:ale_go_go111module = 'off'
let b:parent_dir = ale#path#Simplify(g:dir . '/..')
let b:git_dir = b:parent_dir . '/.git'
if !isdirectory(b:git_dir)
call mkdir(b:git_dir)
endif
AssertLSPProject b:parent_dir
call delete(b:git_dir, 'd')
unlet! b:parent_dir
unlet! b:git_dir

View File

@ -14,6 +14,16 @@ Execute(The default commands should be correct):
\ ale#path#CdString(expand('%:p:h'))
\ . 'go test -c -o /dev/null ./'
Execute(Go environment variables should be supported):
let b:ale_go_go111module = 'on'
AssertLinter 'go',
\ ale#path#CdString(expand('%:p:h'))
\ . ale#Env('GO111MODULE', 'on')
\ . 'go test -c -o /dev/null ./'
unlet! b:ale_go_go111module
Execute(Extra options should be supported):
let g:ale_go_gobuild_options = '--foo-bar'

View File

@ -0,0 +1,19 @@
Before:
call ale#assert#SetUpLinterTest('go', 'gofmt')
call ale#test#SetFilename('../go_files/testfile2.go')
After:
call ale#assert#TearDownLinterTest()
Execute(The default gofmt command should be correct):
AssertLinter 'gofmt',
\ ale#Escape('gofmt') . ' -e %t'
Execute(The gofmt command should support Go environment variables):
let b:ale_go_go111module = 'on'
AssertLinter 'gofmt',
\ ale#Env('GO111MODULE', 'on')
\ . ale#Escape('gofmt') . ' -e %t'
unlet! b:ale_go_go111module

View File

@ -30,6 +30,18 @@ Execute(The golangci-lint callback should use configured options):
\ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --foobar'
Execute(The golangci-lint callback should support environment variables):
let b:ale_go_go111module = 'on'
AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h'))
\ . ale#Env('GO111MODULE', 'on')
\ . ale#Escape('golangci-lint')
\ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --enable-all'
unlet! b:ale_go_go111module
Execute(The golangci-lint `lint_package` option should use the correct command):
let b:ale_go_golangci_lint_package = 1

View File

@ -14,6 +14,7 @@ After:
Restore
unlet! b:ale_completion_enabled
unlet! b:ale_go_go111module
unlet! g:sep
call ale#assert#TearDownLinterTest()
@ -52,6 +53,12 @@ Execute(should ignore go-langserver -gocodecompletion option):
AssertLinter 'go-langserver', ale#Escape('go-langserver') . ' -trace'
Execute(should support Go environment variables):
let b:ale_go_go111module = 'on'
AssertLinter 'go-langserver',
\ ale#Env('GO111MODULE', 'on') . ale#Escape('go-langserver')
Execute(should set go-langserver for go app1):
call ale#test#SetFilename('go_paths/go1/prj1/file.go')

View File

@ -16,3 +16,11 @@ Execute(The golint options should be configurable):
let b:ale_go_golint_options = '--foo'
AssertLinter 'golint', ale#Escape('golint') . ' --foo %t'
Execute(The golint command should support Go environment variables):
let b:ale_go_go111module = 'on'
AssertLinter 'golint',
\ ale#Env('GO111MODULE', 'on') . ale#Escape('golint') . ' %t'
unlet! b:ale_go_go111module

View File

@ -30,6 +30,16 @@ Execute(The gometalinter callback should use configured options):
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' --foobar' . ' .'
Execute(The gometalinter should use configured environment variables):
let b:ale_go_go111module = 'off'
AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h'))
\ . ale#Env('GO111MODULE', 'off')
\ . ale#Escape('gometalinter')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' .'
unlet! b:ale_go_go111module
Execute(The gometalinter `lint_package` option should use the correct command):
let b:ale_go_gometalinter_lint_package = 1

View File

@ -8,6 +8,7 @@ After:
call delete(g:dir . '/.git', 'd')
endif
unlet! b:ale_go_go111module
unlet! b:ale_completion_enabled
call ale#assert#TearDownLinterTest()
@ -34,6 +35,12 @@ Execute(should set gopls options):
AssertLinter 'gopls',
\ ale#Escape('gopls') . ' --mode stdio --trace'
Execute(should support go environment variables):
let b:ale_go_go111module = 'off'
AssertLinter 'gopls',
\ ale#Env('GO111MODULE', 'off') . ale#Escape('gopls') . ' --mode stdio'
Execute(Should return directory for 'go.mod' if found in parent directory):
call ale#test#SetFilename('../go_files/test.go')
@ -44,3 +51,20 @@ Execute(Should return nearest directory with '.git' if found in parent directory
call mkdir(g:dir . '/.git')
AssertLSPProject g:dir
Execute(Should ignore 'go.mod' and return '.git' dir if modules off):
call ale#test#SetFilename('../go_files/test.go')
let b:ale_go_go111module = 'off'
let b:parent_dir = ale#path#Simplify(g:dir . '/..')
let b:git_dir = b:parent_dir . '/.git'
if !isdirectory(b:git_dir)
call mkdir(b:git_dir)
endif
AssertLSPProject b:parent_dir
call delete(b:git_dir, 'd')
unlet! b:parent_dir
unlet! b:git_dir

View File

@ -8,3 +8,12 @@ After:
Execute(The default gosimple command should be correct):
AssertLinter 'gosimple',
\ ale#path#CdString(expand('%:p:h')) . ' gosimple .'
Execute(The gosimple command should support Go environment variables):
let b:ale_go_go111module = 'on'
AssertLinter 'gosimple',
\ ale#path#CdString(expand('%:p:h')) . ' '
\ . ale#Env('GO111MODULE', 'on') . 'gosimple .'
unlet! b:ale_go_go111module

View File

@ -13,3 +13,13 @@ Execute(The gotype callback should ignore test files):
call ale#test#SetFilename('bla_test.go')
AssertLinter 'gotype', ''
Execute(The gotype callback should support Go environment variables):
let b:ale_go_go111module = 'on'
AssertLinter 'gotype',
\ ale#path#CdString(expand('%:p:h')) . ' '
\ . ale#Env('GO111MODULE', 'on')
\ . 'gotype -e .'
unlet! b:ale_go_go111module

View File

@ -17,3 +17,11 @@ Execute(Extra options should be supported):
Execute(The executable should be configurable):
let g:ale_go_go_executable = 'foobar'
AssertLinter 'foobar', ale#path#CdString(expand('%:p:h')) . ' foobar vet .'
Execute(Go environment variables should be supported):
let b:ale_go_go111module = 'on'
AssertLinter 'go',
\ ale#path#CdString(expand('%:p:h')) . ' '
\ . ale#Env('GO111MODULE', 'on')
\ . 'go vet .'
unlet! b:ale_go_go111module

View File

@ -24,3 +24,20 @@ Execute(The staticcheck `lint_package` option should use the correct command):
AssertLinter 'staticcheck',
\ ale#path#CdString(expand('%:p:h')) . 'staticcheck .',
Execute(The staticcheck callback should use the `GO111MODULE` option if set):
let b:ale_go_go111module = 'off'
AssertLinter 'staticcheck',
\ ale#path#CdString(expand('%:p:h'))
\ . ale#Env('GO111MODULE', 'off')
\ . 'staticcheck '
\ . ale#Escape(expand('%' . ':t'))
" Test with lint_package option set
let b:ale_go_staticcheck_lint_package = 1
AssertLinter 'staticcheck',
\ ale#path#CdString(expand('%:p:h'))
\ . ale#Env('GO111MODULE', 'off')
\ . 'staticcheck .'
unlet! b:ale_go_go111module

View File

@ -5,6 +5,7 @@ Before:
" Use an invalid global executable, so we don't match it.
let g:ale_go_gofmt_executable = 'xxxinvalid'
let g:ale_go_gofmt_options = ''
let g:ale_go_go111module = ''
call ale#test#SetDirectory('/testplugin/test/fixers')
@ -38,3 +39,16 @@ Execute(The gofmt callback should include custom gofmt options):
\ . ' %t',
\ },
\ ale#fixers#gofmt#Fix(bufnr(''))
Execute(The gofmt callback should support Go environment variables):
let g:ale_go_go111module = 'off'
call ale#test#SetFilename('../go_files/testfile.go')
AssertEqual
\ {
\ 'read_temporary_file': 1,
\ 'command': ale#Env('GO111MODULE', 'off')
\ . ale#Escape('xxxinvalid') . ' -l -w'
\ . ' %t',
\ },
\ ale#fixers#gofmt#Fix(bufnr(''))

View File

@ -5,6 +5,7 @@ Before:
" Use an invalid global executable, so we don't match it.
let g:ale_go_goimports_executable = 'xxxinvalid'
let g:ale_go_goimports_options = ''
let g:ale_go_go111module = ''
call ale#test#SetDirectory('/testplugin/test/fixers')
call ale#test#SetFilename('../go_files/testfile.go')
@ -39,3 +40,16 @@ Execute(The goimports callback should include extra options):
\ 'command': ale#Escape(g:ale_go_goimports_executable) . ' -l -w -srcdir %s --xxx %t'
\ },
\ ale#fixers#goimports#Fix(bufnr(''))
Execute(The goimports callback should support Go environment variables):
let g:ale_go_goimports_executable = has('win32') ? 'cmd' : 'echo'
let g:ale_go_go111module = 'on'
AssertEqual
\ {
\ 'read_temporary_file': 1,
\ 'command': ale#Env('GO111MODULE', 'on')
\ . ale#Escape(g:ale_go_goimports_executable)
\ . ' -l -w -srcdir %s %t'
\ },
\ ale#fixers#goimports#Fix(bufnr(''))

View File

@ -3,6 +3,7 @@ Before:
" Use an invalid global executable, so we don't match it.
let g:ale_go_go_executable = 'xxxinvalid'
let g:ale_go_go111module = ''
call ale#test#SetDirectory('/testplugin/test/fixers')
After:
@ -12,7 +13,7 @@ After:
Execute(The gomod callback should return the correct default values):
call ale#test#SetFilename('../go_files/go.mod')
setl ft=gomod
setl filetype=gomod
AssertEqual
\ {
@ -22,3 +23,16 @@ Execute(The gomod callback should return the correct default values):
\ . ' %t',
\ },
\ ale#fixers#gomod#Fix(bufnr(''))
Execute(The gomod callback should support Go environment variables):
call ale#test#SetFilename('../go_files/go.mod')
setl filetype=gomod
let g:ale_go_go111module = 'on'
AssertEqual
\ {
\ 'read_temporary_file': 1,
\ 'command': ale#Env('GO111MODULE', 'on')
\ . ale#Escape('xxxinvalid') . ' mod edit -fmt %t'
\ },
\ ale#fixers#gomod#Fix(bufnr(''))