diff --git a/ale_linters/cs/mcsc.vim b/ale_linters/cs/mcsc.vim index 8a78d3b3..8e84620c 100644 --- a/ale_linters/cs/mcsc.vim +++ b/ale_linters/cs/mcsc.vim @@ -29,7 +29,7 @@ function! ale_linters#cs#mcsc#GetCommand(buffer) abort \ : '' " register temporary module target file with ale - let l:out = tempname() + let l:out = ale#util#Tempname() call ale#engine#ManageFile(a:buffer, l:out) " The code is compiled as a module and the output is redirected to a diff --git a/ale_linters/cuda/nvcc.vim b/ale_linters/cuda/nvcc.vim index 7aaa5cc3..3764fe9d 100644 --- a/ale_linters/cuda/nvcc.vim +++ b/ale_linters/cuda/nvcc.vim @@ -10,7 +10,7 @@ endfunction function! ale_linters#cuda#nvcc#GetCommand(buffer) abort " Unused: use ale#util#nul_file - " let l:output_file = tempname() . '.ii' + " let l:output_file = ale#util#Tempname() . '.ii' " call ale#engine#ManageFile(a:buffer, l:output_file) return ale#Escape(ale_linters#cuda#nvcc#GetExecutable(a:buffer)) diff --git a/ale_linters/elm/make.vim b/ale_linters/elm/make.vim index cc14fe4e..d5bc19eb 100644 --- a/ale_linters/elm/make.vim +++ b/ale_linters/elm/make.vim @@ -128,14 +128,7 @@ function! ale_linters#elm#make#HandleElm018Line(line, output) abort endfunction function! ale_linters#elm#make#FileIsBuffer(path) abort - let l:is_windows = has('win32') - let l:temp_dir = l:is_windows ? $TMP : $TMPDIR - - if has('win32') - return a:path[0:len(l:temp_dir) - 1] is? l:temp_dir - else - return a:path[0:len(l:temp_dir) - 1] is# l:temp_dir - endif + return ale#path#IsTempName(a:path) endfunction function! ale_linters#elm#make#ParseMessage(message) abort diff --git a/ale_linters/erlang/erlc.vim b/ale_linters/erlang/erlc.vim index bddb175d..0bdb4dea 100644 --- a/ale_linters/erlang/erlc.vim +++ b/ale_linters/erlang/erlc.vim @@ -3,7 +3,7 @@ let g:ale_erlang_erlc_options = get(g:, 'ale_erlang_erlc_options', '') function! ale_linters#erlang#erlc#GetCommand(buffer) abort - let l:output_file = tempname() + let l:output_file = ale#util#Tempname() call ale#engine#ManageFile(a:buffer, l:output_file) return 'erlc -o ' . ale#Escape(l:output_file) diff --git a/ale_linters/thrift/thrift.vim b/ale_linters/thrift/thrift.vim index 2f62570a..741e80ab 100644 --- a/ale_linters/thrift/thrift.vim +++ b/ale_linters/thrift/thrift.vim @@ -20,7 +20,7 @@ function! ale_linters#thrift#thrift#GetCommand(buffer) abort let l:generators = ['cpp'] endif - let l:output_dir = tempname() + let l:output_dir = ale#util#Tempname() call mkdir(l:output_dir) call ale#engine#ManageDirectory(a:buffer, l:output_dir) diff --git a/ale_linters/verilog/verilator.vim b/ale_linters/verilog/verilator.vim index 6053da09..83d5f59d 100644 --- a/ale_linters/verilog/verilator.vim +++ b/ale_linters/verilog/verilator.vim @@ -7,7 +7,7 @@ if !exists('g:ale_verilog_verilator_options') endif function! ale_linters#verilog#verilator#GetCommand(buffer) abort - let l:filename = tempname() . '_verilator_linted.v' + let l:filename = ale#util#Tempname() . '_verilator_linted.v' " Create a special filename, so we can detect it in the handler. call ale#engine#ManageFile(a:buffer, l:filename) diff --git a/autoload/ale/command.vim b/autoload/ale/command.vim index 558fe233..18457e0b 100644 --- a/autoload/ale/command.vim +++ b/autoload/ale/command.vim @@ -13,7 +13,7 @@ function! s:TemporaryFilename(buffer) abort " Create a temporary filename, / " The file itself will not be created by this function. - return tempname() . (has('win32') ? '\' : '/') . l:filename + return ale#util#Tempname() . (has('win32') ? '\' : '/') . l:filename endfunction " Given a command string, replace every... diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index d97b6937..247dcbe7 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -98,7 +98,7 @@ endfunction " Create a new temporary directory and manage it in one go. function! ale#engine#CreateDirectory(buffer) abort - let l:temporary_directory = tempname() + let l:temporary_directory = ale#util#Tempname() " Create the temporary directory for the file, unreadable by 'other' " users. call mkdir(l:temporary_directory, '', 0750) diff --git a/autoload/ale/handlers/haskell.vim b/autoload/ale/handlers/haskell.vim index 8a0d0013..9223b650 100644 --- a/autoload/ale/handlers/haskell.vim +++ b/autoload/ale/handlers/haskell.vim @@ -2,7 +2,7 @@ " Description: Error handling for the format GHC outputs. " Remember the directory used for temporary files for Vim. -let s:temp_dir = fnamemodify(tempname(), ':h') +let s:temp_dir = fnamemodify(ale#util#Tempname(), ':h') " Build part of a regular expression for matching ALE temporary filenames. let s:temp_regex_prefix = \ '\M' diff --git a/autoload/ale/path.vim b/autoload/ale/path.vim index 91832b35..45da3709 100644 --- a/autoload/ale/path.vim +++ b/autoload/ale/path.vim @@ -84,7 +84,7 @@ function! ale#path#IsAbsolute(filename) abort return a:filename[:0] is# '/' || a:filename[1:2] is# ':\' endfunction -let s:temp_dir = ale#path#Simplify(fnamemodify(tempname(), ':h')) +let s:temp_dir = ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h')) " Given a filename, return 1 if the file represents some temporary file " created by Vim. diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim index 267b0587..93b997ea 100644 --- a/autoload/ale/util.vim +++ b/autoload/ale/util.vim @@ -277,6 +277,25 @@ function! ale#util#InSandbox() abort return 0 endfunction +function! ale#util#Tempname() abort + let l:clear_tempdir = 0 + + if has('unix') && empty($TMPDIR) + let l:clear_tempdir = 1 + let $TMPDIR = '/tmp' + endif + + try + let l:name = tempname() " no-custom-checks + finally + if l:clear_tempdir + let $TMPDIR = '' + endif + endtry + + return l:name +endfunction + " Given a single line, or a List of lines, and a single pattern, or a List " of patterns, return all of the matches for the lines(s) from the given " patterns, using matchlist(). diff --git a/doc/ale-development.txt b/doc/ale-development.txt index 841371c7..f97bdee4 100644 --- a/doc/ale-development.txt +++ b/doc/ale-development.txt @@ -111,6 +111,9 @@ these are reported with ALE's `custom-linting-rules` script. See * Don't use the `shellescape()` function. It doesn't escape arguments properly on Windows. Use `ale#Escape()` instead, which will avoid escaping where it isn't needed, and generally escape arguments better on Windows. +* Don't use the `tempname()` function. It doesn't work when `$TMPDIR` isn't + set. Use `ale#util#Tempname()` instead, which temporarily sets `$TMPDIR` + appropriately where needed. Apply the following guidelines when writing Vader test files. diff --git a/plugin/ale.vim b/plugin/ale.vim index 3bd12015..511faf85 100644 --- a/plugin/ale.vim +++ b/plugin/ale.vim @@ -35,12 +35,6 @@ endif " Set this flag so that other plugins can use it, like airline. let g:loaded_ale = 1 -" Set the TMPDIR environment variable if it is not set automatically. -" This can automatically fix some environments. -if has('unix') && empty($TMPDIR) - let $TMPDIR = '/tmp' -endif - " This global variable is used internally by ALE for tracking information for " each buffer which linters are being run against. let g:ale_buffer_info = {} diff --git a/test/handler/test_elmmake_handler.vader b/test/handler/test_elmmake_handler.vader index 41c9646f..f5906a8b 100644 --- a/test/handler/test_elmmake_handler.vader +++ b/test/handler/test_elmmake_handler.vader @@ -1,10 +1,7 @@ Before: - let b:tmp = has('win32') ? substitute($TMP, '\\', '\\\\', 'g') : $TMPDIR - runtime ale_linters/elm/make.vim After: - unlet! b:tmp unlet! g:config_error_lines call ale#linter#Reset() @@ -22,12 +19,12 @@ Execute(The elm-make handler should parse Elm 0.19 general problems correctly): \ } \ ], \ ale_linters#elm#make#Handle(347, [ - \ '{ - \ "type": "error", - \ "path": "' . b:tmp . '/Module.elm", - \ "title": "UNKNOWN IMPORT", - \ "message": ["error details\n\n", { "string": "styled details" }] - \ }' + \ json_encode({ + \ 'type': 'error', + \ 'path': ale#util#Tempname() . '/Module.elm', + \ 'title': 'UNKNOWN IMPORT', + \ 'message': ["error details\n\n", { 'string': 'styled details' }] + \ }), \ ]) Execute(The elm-make handler should parse Elm 0.19 compilation errors correctly): @@ -47,7 +44,7 @@ Execute(The elm-make handler should parse Elm 0.19 compilation errors correctly) \ 'end_lnum': 407, \ 'end_col': 17, \ 'type': 'E', - \ 'text': "error details 2", + \ 'text': 'error details 2', \ }, \ { \ 'lnum': 406, @@ -55,35 +52,35 @@ Execute(The elm-make handler should parse Elm 0.19 compilation errors correctly) \ 'end_lnum': 406, \ 'end_col': 93, \ 'type': 'E', - \ 'text': "error details 3", + \ 'text': 'error details 3', \ }, \ ], \ ale_linters#elm#make#Handle(347, [ - \ '{ - \ "type": "compile-errors", - \ "errors": [ + \ json_encode({ + \ 'type': 'compile-errors', + \ 'errors': [ \ { - \ "path": "' . b:tmp . '/Module.elm", - \ "problems": [ + \ 'path': ale#util#Tempname() . '/Module.elm', + \ 'problems': [ \ { - \ "title": "TYPE MISMATCH", - \ "message": ["error details 1\n\n", { "string": "styled details" }], - \ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } } + \ 'title': 'TYPE MISMATCH', + \ 'message': ["error details 1\n\n", { 'string': 'styled details' }], + \ 'region': { 'start': { 'line': 404, 'column': 1 }, 'end': { 'line': 408, 'column': 18 } } \ }, \ { - \ "title": "TYPE MISMATCH", - \ "message": ["error details 2"], - \ "region": { "start": {"line": 406, "column": 5}, "end": {"line": 407, "column": 17 } } + \ 'title': 'TYPE MISMATCH', + \ 'message': ['error details 2'], + \ 'region': { 'start': {'line': 406, 'column': 5}, 'end': {'line': 407, 'column': 17 } } \ }, \ { - \ "title": "TYPE MISMATCH", - \ "message": ["error details 3"], - \ "region": { "start": { "line": 406, "column": 5}, "end": {"line": 406, "column": 93 } } + \ 'title': 'TYPE MISMATCH', + \ 'message': ['error details 3'], + \ 'region': { 'start': { 'line': 406, 'column': 5}, 'end': {'line': 406, 'column': 93 } } \ } \ ] \ } \ ] - \ }' + \ }), \ ]) Execute(The elm-make handler should handle errors in Elm 0.19 imported modules): @@ -109,33 +106,33 @@ Execute(The elm-make handler should handle errors in Elm 0.19 imported modules): \ }, \ ], \ ale_linters#elm#make#Handle(347, [ - \ '{ - \ "type": "error", - \ "path": "src/Module.elm", - \ "title": "UNKNOWN IMPORT", - \ "message": ["error details\n\n", { "string": "styled details" }] - \ }', - \ '{ - \ "type": "error", - \ "path": null, - \ "title": "UNKNOWN IMPORT", - \ "message": ["error details\n\n", { "string": "styled details" }] - \ }', - \ '{ - \ "type": "compile-errors", - \ "errors": [ + \ json_encode({ + \ 'type': 'error', + \ 'path': 'src/Module.elm', + \ 'title': 'UNKNOWN IMPORT', + \ 'message': ["error details\n\n", { 'string': 'styled details' }] + \ }), + \ json_encode({ + \ 'type': 'error', + \ 'path': v:null, + \ 'title': 'UNKNOWN IMPORT', + \ 'message': ["error details\n\n", { 'string': 'styled details' }] + \ }), + \ json_encode({ + \ 'type': 'compile-errors', + \ 'errors': [ \ { - \ "path": "src/Module.elm", - \ "problems": [ + \ 'path': 'src/Module.elm', + \ 'problems': [ \ { - \ "title": "TYPE MISMATCH", - \ "message": ["error details\n\n", { "string": "styled details" }], - \ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } } + \ 'title': 'TYPE MISMATCH', + \ 'message': ["error details\n\n", { 'string': 'styled details' }], + \ 'region': { 'start': { 'line': 404, 'column': 1 }, 'end': { 'line': 408, 'column': 18 } } \ } \ ] \ } \ ] - \ }' + \ }), \ ]) @@ -182,45 +179,45 @@ Execute(The elm-make handler should parse Elm 0.18 compilation errors correctly) \ }, \ ], \ ale_linters#elm#make#Handle(347, [ - \ '[ + \ json_encode([ \ { - \ "tag": "unused import", - \ "overview": "warning overview", - \ "details": "warning details", - \ "region": {"start": { "line": 33, "column": 1 }, "end": { "line": 33, "column": 19 } }, - \ "type": "warning", - \ "file": "' . b:tmp . '/Module.elm" + \ 'tag': 'unused import', + \ 'overview': 'warning overview', + \ 'details': 'warning details', + \ 'region': {'start': { 'line': 33, 'column': 1 }, 'end': { 'line': 33, 'column': 19 } }, + \ 'type': 'warning', + \ 'file': ale#util#Tempname() . '/Module.elm', \ } - \ ]', - \ '[ + \ ]), + \ json_encode([ \ { - \ "tag": "TYPE MISMATCH", - \ "overview": "error overview 1", - \ "subregion": { "start": { "line": 406, "column": 5 }, "end": { "line": 408, "column": 18 } }, - \ "details": "error details 1", - \ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } }, - \ "type": "error", - \ "file":"' . b:tmp . '/Module.elm" + \ 'tag': 'TYPE MISMATCH', + \ 'overview': 'error overview 1', + \ 'subregion': { 'start': { 'line': 406, 'column': 5 }, 'end': { 'line': 408, 'column': 18 } }, + \ 'details': 'error details 1', + \ 'region': { 'start': { 'line': 404, 'column': 1 }, 'end': { 'line': 408, 'column': 18 } }, + \ 'type': 'error', + \ 'file': ale#util#Tempname() . '/Module.elm', \ }, \ { - \ "tag": "TYPE MISMATCH", - \ "overview": "error overview 2", - \ "subregion": { "start": { "line": 407, "column": 12 }, "end": { "line": 407, "column": 17 } }, - \ "details": "error details 2", - \ "region": { "start": { "line": 406, "column": 5}, "end": { "line": 407, "column": 17 } }, - \ "type":"error", - \ "file":"' . b:tmp . '/Module.elm" + \ 'tag': 'TYPE MISMATCH', + \ 'overview': 'error overview 2', + \ 'subregion': { 'start': { 'line': 407, 'column': 12 }, 'end': { 'line': 407, 'column': 17 } }, + \ 'details': 'error details 2', + \ 'region': { 'start': { 'line': 406, 'column': 5}, 'end': { 'line': 407, 'column': 17 } }, + \ 'type':'error', + \ 'file': ale#util#Tempname() . '/Module.elm', \ }, \ { - \ "tag": "TYPE MISMATCH", - \ "overview": "error overview 3", - \ "subregion": { "start": { "line": 406, "column": 88 }, "end": { "line": 406, "column": 93 } }, - \ "details": "error details 3", - \ "region": { "start": { "line": 406, "column": 5 }, "end": { "line": 406, "column": 93 } }, - \ "type":"error", - \ "file":"' . b:tmp . '/Module.elm" + \ 'tag': 'TYPE MISMATCH', + \ 'overview': 'error overview 3', + \ 'subregion': { 'start': { 'line': 406, 'column': 88 }, 'end': { 'line': 406, 'column': 93 } }, + \ 'details': 'error details 3', + \ 'region': { 'start': { 'line': 406, 'column': 5 }, 'end': { 'line': 406, 'column': 93 } }, + \ 'type':'error', + \ 'file': ale#util#Tempname() . '/Module.elm', \ } - \ ]' + \ ]), \ ]) Execute(The elm-make handler should handle errors in Elm 0.18 imported modules): @@ -229,29 +226,29 @@ Execute(The elm-make handler should handle errors in Elm 0.18 imported modules): \ { \ 'lnum': 1, \ 'type': 'E', - \ 'text': "src/Module.elm:33 - error overview", + \ 'text': 'src/Module.elm:33 - error overview', \ 'detail': "src/Module.elm:33 ----------\n\nerror overview\n\nerror details" \ } \ ], \ ale_linters#elm#make#Handle(347, [ - \ '[ + \ json_encode([ \ { - \ "tag": "unused import", - \ "overview": "warning overview", - \ "details": "warning details", - \ "region": {"start": { "line": 33, "column": 1 }, "end": { "line": 33, "column": 19 } }, - \ "type": "warning", - \ "file": "src/Module.elm" + \ 'tag': 'unused import', + \ 'overview': 'warning overview', + \ 'details': 'warning details', + \ 'region': {'start': { 'line': 33, 'column': 1 }, 'end': { 'line': 33, 'column': 19 } }, + \ 'type': 'warning', + \ 'file': 'src/Module.elm', \ }, \ { - \ "tag": "type error", - \ "overview": "error overview", - \ "details": "error details", - \ "region": {"start": { "line": 33, "column": 1 }, "end": { "line": 33, "column": 19 } }, - \ "type": "error", - \ "file": "src/Module.elm" + \ 'tag': 'type error', + \ 'overview': 'error overview', + \ 'details': 'error details', + \ 'region': {'start': { 'line': 33, 'column': 1 }, 'end': { 'line': 33, 'column': 19 } }, + \ 'type': 'error', + \ 'file': 'src/Module.elm', \ } - \ ]', + \ ]), \ ]) " Generic @@ -275,21 +272,21 @@ Execute(The elm-make handler should put an error on the first line if a line can \ }, \ ], \ ale_linters#elm#make#Handle(347, [ - \ '{ - \ "type": "compile-errors", - \ "errors": [ + \ json_encode({ + \ 'type': 'compile-errors', + \ 'errors': [ \ { - \ "path": "' . b:tmp . '/Module.elm", - \ "problems": [ + \ 'path': ale#util#Tempname() . '/Module.elm', + \ 'problems': [ \ { - \ "title": "TYPE MISMATCH", - \ "message": ["error details 1\n\n", { "string": "styled details" }], - \ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } } + \ 'title': 'TYPE MISMATCH', + \ 'message': ["error details 1\n\n", { 'string': 'styled details' }], + \ 'region': { 'start': { 'line': 404, 'column': 1 }, 'end': { 'line': 408, 'column': 18 } } \ } \ ] \ } \ ] - \ }', + \ }), \ 'Not JSON', \ 'Also not JSON', \ ]) diff --git a/test/script/custom-linting-rules b/test/script/custom-linting-rules index 0d1a0fd1..51cf5680 100755 --- a/test/script/custom-linting-rules +++ b/test/script/custom-linting-rules @@ -87,6 +87,7 @@ check_errors $'\t' 'Use four spaces, not tabs' check_errors 'let g:ale_\w\+_\w\+_args =' 'Name your option g:ale___options instead' check_errors 'shellescape(' 'Use ale#Escape instead of shellescape' check_errors 'simplify(' 'Use ale#path#Simplify instead of simplify' +check_errors 'tempname(' 'Use ale#util#Tempname instead of tempname' check_errors "expand(['\"]%" "Use expand('#' . a:buffer . '...') instead. You might get a filename for the wrong buffer." check_errors 'getcwd()' "Do not use getcwd(), as it could run from the wrong buffer. Use expand('#' . a:buffer . ':p:h') instead." check_errors '==#' "Use 'is#' instead of '==#'. 0 ==# 'foobar' is true" diff --git a/test/test_tmpdir_init.vader b/test/test_tmpdir_init.vader deleted file mode 100644 index 23326dcc..00000000 --- a/test/test_tmpdir_init.vader +++ /dev/null @@ -1,4 +0,0 @@ -Execute($TMPDIR should be set to a default value if unset): - if has('unix') - AssertEqual '/tmp', $TMPDIR - endif diff --git a/test/test_tmpdir_wrapper.vader b/test/test_tmpdir_wrapper.vader new file mode 100644 index 00000000..4d87061f --- /dev/null +++ b/test/test_tmpdir_wrapper.vader @@ -0,0 +1,13 @@ +Before: + Save $TMPDIR + +After: + Restore + +Execute(ale#util#Tempname should create files in /tmp if $TMPDIR isn't set): + if has('unix') + let $TMPDIR = '' + Assert ale#util#Tempname() =~# '^/tmp' + " We should unlet the environment variable again. + AssertEqual '', $TMPDIR + endif diff --git a/test/vimrc b/test/vimrc index 970e20ee..9548f861 100644 --- a/test/vimrc +++ b/test/vimrc @@ -35,7 +35,3 @@ set ttimeoutlen=0 execute 'set encoding=utf-8' let g:mapleader=',' - -" Clear the TMPDIR value for tests. -" The plugin should set this to /tmp by default, which we will test. -let $TMPDIR = ''