Fix #1716 - Replace tempdir() with a wrapper to preserve TMPDIR

This commit is contained in:
w0rp 2018-07-12 13:05:59 +01:00
parent 6ef31073dd
commit ac0abc7c1f
No known key found for this signature in database
GPG Key ID: 0FC1ECAA8C81CD83
18 changed files with 145 additions and 133 deletions

View File

@ -29,7 +29,7 @@ function! ale_linters#cs#mcsc#GetCommand(buffer) abort
\ : '' \ : ''
" register temporary module target file with ale " 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) call ale#engine#ManageFile(a:buffer, l:out)
" The code is compiled as a module and the output is redirected to a " The code is compiled as a module and the output is redirected to a

View File

@ -10,7 +10,7 @@ endfunction
function! ale_linters#cuda#nvcc#GetCommand(buffer) abort function! ale_linters#cuda#nvcc#GetCommand(buffer) abort
" Unused: use ale#util#nul_file " 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) " call ale#engine#ManageFile(a:buffer, l:output_file)
return ale#Escape(ale_linters#cuda#nvcc#GetExecutable(a:buffer)) return ale#Escape(ale_linters#cuda#nvcc#GetExecutable(a:buffer))

View File

@ -128,14 +128,7 @@ function! ale_linters#elm#make#HandleElm018Line(line, output) abort
endfunction endfunction
function! ale_linters#elm#make#FileIsBuffer(path) abort function! ale_linters#elm#make#FileIsBuffer(path) abort
let l:is_windows = has('win32') return ale#path#IsTempName(a:path)
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
endfunction endfunction
function! ale_linters#elm#make#ParseMessage(message) abort function! ale_linters#elm#make#ParseMessage(message) abort

View File

@ -3,7 +3,7 @@
let g:ale_erlang_erlc_options = get(g:, 'ale_erlang_erlc_options', '') let g:ale_erlang_erlc_options = get(g:, 'ale_erlang_erlc_options', '')
function! ale_linters#erlang#erlc#GetCommand(buffer) abort 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) call ale#engine#ManageFile(a:buffer, l:output_file)
return 'erlc -o ' . ale#Escape(l:output_file) return 'erlc -o ' . ale#Escape(l:output_file)

View File

@ -20,7 +20,7 @@ function! ale_linters#thrift#thrift#GetCommand(buffer) abort
let l:generators = ['cpp'] let l:generators = ['cpp']
endif endif
let l:output_dir = tempname() let l:output_dir = ale#util#Tempname()
call mkdir(l:output_dir) call mkdir(l:output_dir)
call ale#engine#ManageDirectory(a:buffer, l:output_dir) call ale#engine#ManageDirectory(a:buffer, l:output_dir)

View File

@ -7,7 +7,7 @@ if !exists('g:ale_verilog_verilator_options')
endif endif
function! ale_linters#verilog#verilator#GetCommand(buffer) abort 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. " Create a special filename, so we can detect it in the handler.
call ale#engine#ManageFile(a:buffer, l:filename) call ale#engine#ManageFile(a:buffer, l:filename)

View File

@ -13,7 +13,7 @@ function! s:TemporaryFilename(buffer) abort
" Create a temporary filename, <temp_dir>/<original_basename> " Create a temporary filename, <temp_dir>/<original_basename>
" The file itself will not be created by this function. " 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 endfunction
" Given a command string, replace every... " Given a command string, replace every...

View File

@ -98,7 +98,7 @@ endfunction
" Create a new temporary directory and manage it in one go. " Create a new temporary directory and manage it in one go.
function! ale#engine#CreateDirectory(buffer) abort 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' " Create the temporary directory for the file, unreadable by 'other'
" users. " users.
call mkdir(l:temporary_directory, '', 0750) call mkdir(l:temporary_directory, '', 0750)

View File

@ -2,7 +2,7 @@
" Description: Error handling for the format GHC outputs. " Description: Error handling for the format GHC outputs.
" Remember the directory used for temporary files for Vim. " 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. " Build part of a regular expression for matching ALE temporary filenames.
let s:temp_regex_prefix = let s:temp_regex_prefix =
\ '\M' \ '\M'

View File

@ -84,7 +84,7 @@ function! ale#path#IsAbsolute(filename) abort
return a:filename[:0] is# '/' || a:filename[1:2] is# ':\' return a:filename[:0] is# '/' || a:filename[1:2] is# ':\'
endfunction 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 " Given a filename, return 1 if the file represents some temporary file
" created by Vim. " created by Vim.

View File

@ -277,6 +277,25 @@ function! ale#util#InSandbox() abort
return 0 return 0
endfunction 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 " 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 " of patterns, return all of the matches for the lines(s) from the given
" patterns, using matchlist(). " patterns, using matchlist().

View File

@ -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 * Don't use the `shellescape()` function. It doesn't escape arguments properly
on Windows. Use `ale#Escape()` instead, which will avoid escaping where it on Windows. Use `ale#Escape()` instead, which will avoid escaping where it
isn't needed, and generally escape arguments better on Windows. 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. Apply the following guidelines when writing Vader test files.

View File

@ -35,12 +35,6 @@ endif
" Set this flag so that other plugins can use it, like airline. " Set this flag so that other plugins can use it, like airline.
let g:loaded_ale = 1 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 " This global variable is used internally by ALE for tracking information for
" each buffer which linters are being run against. " each buffer which linters are being run against.
let g:ale_buffer_info = {} let g:ale_buffer_info = {}

View File

@ -1,10 +1,7 @@
Before: Before:
let b:tmp = has('win32') ? substitute($TMP, '\\', '\\\\', 'g') : $TMPDIR
runtime ale_linters/elm/make.vim runtime ale_linters/elm/make.vim
After: After:
unlet! b:tmp
unlet! g:config_error_lines unlet! g:config_error_lines
call ale#linter#Reset() 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, [ \ ale_linters#elm#make#Handle(347, [
\ '{ \ json_encode({
\ "type": "error", \ 'type': 'error',
\ "path": "' . b:tmp . '/Module.elm", \ 'path': ale#util#Tempname() . '/Module.elm',
\ "title": "UNKNOWN IMPORT", \ 'title': 'UNKNOWN IMPORT',
\ "message": ["error details\n\n", { "string": "styled details" }] \ 'message': ["error details\n\n", { 'string': 'styled details' }]
\ }' \ }),
\ ]) \ ])
Execute(The elm-make handler should parse Elm 0.19 compilation errors correctly): 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_lnum': 407,
\ 'end_col': 17, \ 'end_col': 17,
\ 'type': 'E', \ 'type': 'E',
\ 'text': "error details 2", \ 'text': 'error details 2',
\ }, \ },
\ { \ {
\ 'lnum': 406, \ 'lnum': 406,
@ -55,35 +52,35 @@ Execute(The elm-make handler should parse Elm 0.19 compilation errors correctly)
\ 'end_lnum': 406, \ 'end_lnum': 406,
\ 'end_col': 93, \ 'end_col': 93,
\ 'type': 'E', \ 'type': 'E',
\ 'text': "error details 3", \ 'text': 'error details 3',
\ }, \ },
\ ], \ ],
\ ale_linters#elm#make#Handle(347, [ \ ale_linters#elm#make#Handle(347, [
\ '{ \ json_encode({
\ "type": "compile-errors", \ 'type': 'compile-errors',
\ "errors": [ \ 'errors': [
\ { \ {
\ "path": "' . b:tmp . '/Module.elm", \ 'path': ale#util#Tempname() . '/Module.elm',
\ "problems": [ \ 'problems': [
\ { \ {
\ "title": "TYPE MISMATCH", \ 'title': 'TYPE MISMATCH',
\ "message": ["error details 1\n\n", { "string": "styled details" }], \ 'message': ["error details 1\n\n", { 'string': 'styled details' }],
\ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } } \ 'region': { 'start': { 'line': 404, 'column': 1 }, 'end': { 'line': 408, 'column': 18 } }
\ }, \ },
\ { \ {
\ "title": "TYPE MISMATCH", \ 'title': 'TYPE MISMATCH',
\ "message": ["error details 2"], \ 'message': ['error details 2'],
\ "region": { "start": {"line": 406, "column": 5}, "end": {"line": 407, "column": 17 } } \ 'region': { 'start': {'line': 406, 'column': 5}, 'end': {'line': 407, 'column': 17 } }
\ }, \ },
\ { \ {
\ "title": "TYPE MISMATCH", \ 'title': 'TYPE MISMATCH',
\ "message": ["error details 3"], \ 'message': ['error details 3'],
\ "region": { "start": { "line": 406, "column": 5}, "end": {"line": 406, "column": 93 } } \ '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): 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, [ \ ale_linters#elm#make#Handle(347, [
\ '{ \ json_encode({
\ "type": "error", \ 'type': 'error',
\ "path": "src/Module.elm", \ 'path': 'src/Module.elm',
\ "title": "UNKNOWN IMPORT", \ 'title': 'UNKNOWN IMPORT',
\ "message": ["error details\n\n", { "string": "styled details" }] \ 'message': ["error details\n\n", { 'string': 'styled details' }]
\ }', \ }),
\ '{ \ json_encode({
\ "type": "error", \ 'type': 'error',
\ "path": null, \ 'path': v:null,
\ "title": "UNKNOWN IMPORT", \ 'title': 'UNKNOWN IMPORT',
\ "message": ["error details\n\n", { "string": "styled details" }] \ 'message': ["error details\n\n", { 'string': 'styled details' }]
\ }', \ }),
\ '{ \ json_encode({
\ "type": "compile-errors", \ 'type': 'compile-errors',
\ "errors": [ \ 'errors': [
\ { \ {
\ "path": "src/Module.elm", \ 'path': 'src/Module.elm',
\ "problems": [ \ 'problems': [
\ { \ {
\ "title": "TYPE MISMATCH", \ 'title': 'TYPE MISMATCH',
\ "message": ["error details\n\n", { "string": "styled details" }], \ 'message': ["error details\n\n", { 'string': 'styled details' }],
\ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } } \ '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, [ \ ale_linters#elm#make#Handle(347, [
\ '[ \ json_encode([
\ { \ {
\ "tag": "unused import", \ 'tag': 'unused import',
\ "overview": "warning overview", \ 'overview': 'warning overview',
\ "details": "warning details", \ 'details': 'warning details',
\ "region": {"start": { "line": 33, "column": 1 }, "end": { "line": 33, "column": 19 } }, \ 'region': {'start': { 'line': 33, 'column': 1 }, 'end': { 'line': 33, 'column': 19 } },
\ "type": "warning", \ 'type': 'warning',
\ "file": "' . b:tmp . '/Module.elm" \ 'file': ale#util#Tempname() . '/Module.elm',
\ } \ }
\ ]', \ ]),
\ '[ \ json_encode([
\ { \ {
\ "tag": "TYPE MISMATCH", \ 'tag': 'TYPE MISMATCH',
\ "overview": "error overview 1", \ 'overview': 'error overview 1',
\ "subregion": { "start": { "line": 406, "column": 5 }, "end": { "line": 408, "column": 18 } }, \ 'subregion': { 'start': { 'line': 406, 'column': 5 }, 'end': { 'line': 408, 'column': 18 } },
\ "details": "error details 1", \ 'details': 'error details 1',
\ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } }, \ 'region': { 'start': { 'line': 404, 'column': 1 }, 'end': { 'line': 408, 'column': 18 } },
\ "type": "error", \ 'type': 'error',
\ "file":"' . b:tmp . '/Module.elm" \ 'file': ale#util#Tempname() . '/Module.elm',
\ }, \ },
\ { \ {
\ "tag": "TYPE MISMATCH", \ 'tag': 'TYPE MISMATCH',
\ "overview": "error overview 2", \ 'overview': 'error overview 2',
\ "subregion": { "start": { "line": 407, "column": 12 }, "end": { "line": 407, "column": 17 } }, \ 'subregion': { 'start': { 'line': 407, 'column': 12 }, 'end': { 'line': 407, 'column': 17 } },
\ "details": "error details 2", \ 'details': 'error details 2',
\ "region": { "start": { "line": 406, "column": 5}, "end": { "line": 407, "column": 17 } }, \ 'region': { 'start': { 'line': 406, 'column': 5}, 'end': { 'line': 407, 'column': 17 } },
\ "type":"error", \ 'type':'error',
\ "file":"' . b:tmp . '/Module.elm" \ 'file': ale#util#Tempname() . '/Module.elm',
\ }, \ },
\ { \ {
\ "tag": "TYPE MISMATCH", \ 'tag': 'TYPE MISMATCH',
\ "overview": "error overview 3", \ 'overview': 'error overview 3',
\ "subregion": { "start": { "line": 406, "column": 88 }, "end": { "line": 406, "column": 93 } }, \ 'subregion': { 'start': { 'line': 406, 'column': 88 }, 'end': { 'line': 406, 'column': 93 } },
\ "details": "error details 3", \ 'details': 'error details 3',
\ "region": { "start": { "line": 406, "column": 5 }, "end": { "line": 406, "column": 93 } }, \ 'region': { 'start': { 'line': 406, 'column': 5 }, 'end': { 'line': 406, 'column': 93 } },
\ "type":"error", \ 'type':'error',
\ "file":"' . b:tmp . '/Module.elm" \ 'file': ale#util#Tempname() . '/Module.elm',
\ } \ }
\ ]' \ ]),
\ ]) \ ])
Execute(The elm-make handler should handle errors in Elm 0.18 imported modules): 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, \ 'lnum': 1,
\ 'type': 'E', \ '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" \ 'detail': "src/Module.elm:33 ----------\n\nerror overview\n\nerror details"
\ } \ }
\ ], \ ],
\ ale_linters#elm#make#Handle(347, [ \ ale_linters#elm#make#Handle(347, [
\ '[ \ json_encode([
\ { \ {
\ "tag": "unused import", \ 'tag': 'unused import',
\ "overview": "warning overview", \ 'overview': 'warning overview',
\ "details": "warning details", \ 'details': 'warning details',
\ "region": {"start": { "line": 33, "column": 1 }, "end": { "line": 33, "column": 19 } }, \ 'region': {'start': { 'line': 33, 'column': 1 }, 'end': { 'line': 33, 'column': 19 } },
\ "type": "warning", \ 'type': 'warning',
\ "file": "src/Module.elm" \ 'file': 'src/Module.elm',
\ }, \ },
\ { \ {
\ "tag": "type error", \ 'tag': 'type error',
\ "overview": "error overview", \ 'overview': 'error overview',
\ "details": "error details", \ 'details': 'error details',
\ "region": {"start": { "line": 33, "column": 1 }, "end": { "line": 33, "column": 19 } }, \ 'region': {'start': { 'line': 33, 'column': 1 }, 'end': { 'line': 33, 'column': 19 } },
\ "type": "error", \ 'type': 'error',
\ "file": "src/Module.elm" \ 'file': 'src/Module.elm',
\ } \ }
\ ]', \ ]),
\ ]) \ ])
" Generic " 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, [ \ ale_linters#elm#make#Handle(347, [
\ '{ \ json_encode({
\ "type": "compile-errors", \ 'type': 'compile-errors',
\ "errors": [ \ 'errors': [
\ { \ {
\ "path": "' . b:tmp . '/Module.elm", \ 'path': ale#util#Tempname() . '/Module.elm',
\ "problems": [ \ 'problems': [
\ { \ {
\ "title": "TYPE MISMATCH", \ 'title': 'TYPE MISMATCH',
\ "message": ["error details 1\n\n", { "string": "styled details" }], \ 'message': ["error details 1\n\n", { 'string': 'styled details' }],
\ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } } \ 'region': { 'start': { 'line': 404, 'column': 1 }, 'end': { 'line': 408, 'column': 18 } }
\ } \ }
\ ] \ ]
\ } \ }
\ ] \ ]
\ }', \ }),
\ 'Not JSON', \ 'Not JSON',
\ 'Also not JSON', \ 'Also not JSON',
\ ]) \ ])

View File

@ -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_<filetype>_<lintername>_options instead' check_errors 'let g:ale_\w\+_\w\+_args =' 'Name your option g:ale_<filetype>_<lintername>_options instead'
check_errors 'shellescape(' 'Use ale#Escape instead of shellescape' check_errors 'shellescape(' 'Use ale#Escape instead of shellescape'
check_errors 'simplify(' 'Use ale#path#Simplify instead of simplify' 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 "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 '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" check_errors '==#' "Use 'is#' instead of '==#'. 0 ==# 'foobar' is true"

View File

@ -1,4 +0,0 @@
Execute($TMPDIR should be set to a default value if unset):
if has('unix')
AssertEqual '/tmp', $TMPDIR
endif

View File

@ -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

View File

@ -35,7 +35,3 @@ set ttimeoutlen=0
execute 'set encoding=utf-8' execute 'set encoding=utf-8'
let g:mapleader=',' let g:mapleader=','
" Clear the TMPDIR value for tests.
" The plugin should set this to /tmp by default, which we will test.
let $TMPDIR = ''