Implement task timeout with default timeout 60 sec (#5)

Terminating a task during its execution can leave the directory in an invalid
state. PlugClean command was updated as well to handle invalid directories.
This commit is contained in:
Junegunn Choi 2013-09-28 12:43:21 +09:00
parent b175e5fc85
commit fe942d61d2
2 changed files with 57 additions and 27 deletions

View File

@ -65,7 +65,12 @@ plugins with `plug#begin(path)` call.
| PlugUpgrade | Upgrade vim-plug itself | | PlugUpgrade | Upgrade vim-plug itself |
| PlugStatus | Check the status of plugins | | PlugStatus | Check the status of plugins |
(Default number of threads = `g:plug_threads` or 16) ### Options for parallel installer
| Flag | Default | Description |
| ---------------- | ------- | --------------------------------- |
| `g:plug_threads` | 16 | Default number of threads to use |
| `g:plug_timeout` | 60 | Time limit of each task in seconds |
### Dependency resolution ### Dependency resolution

View File

@ -284,14 +284,15 @@ function! s:update_serial(pull)
let done[name] = 1 let done[name] = 1
if isdirectory(spec.dir) if isdirectory(spec.dir)
execute 'cd '.spec.dir execute 'cd '.spec.dir
if s:git_valid(spec, 0) let [valid, msg] = s:git_valid(spec, 0)
if valid
let result = a:pull ? let result = a:pull ?
\ s:system( \ s:system(
\ printf('git checkout -q %s 2>&1 && git pull origin %s 2>&1', \ printf('git checkout -q %s 2>&1 && git pull origin %s 2>&1',
\ spec.branch, spec.branch)) : 'Already installed' \ spec.branch, spec.branch)) : 'Already installed'
let error = a:pull ? v:shell_error != 0 : 0 let error = a:pull ? v:shell_error != 0 : 0
else else
let result = "PlugClean required. Invalid remote." let result = msg
let error = 1 let error = 1
endif endif
else else
@ -329,12 +330,14 @@ function! s:update_parallel(pull, threads)
ruby << EOF ruby << EOF
require 'thread' require 'thread'
require 'fileutils' require 'fileutils'
require 'timeout'
st = Time.now st = Time.now
iswin = VIM::evaluate('s:is_win').to_i == 1 iswin = VIM::evaluate('s:is_win').to_i == 1
cd = iswin ? 'cd /d' : 'cd' cd = iswin ? 'cd /d' : 'cd'
pull = VIM::evaluate('a:pull').to_i == 1 pull = VIM::evaluate('a:pull').to_i == 1
base = VIM::evaluate('g:plug_home') base = VIM::evaluate('g:plug_home')
all = VIM::evaluate('copy(g:plugs)') all = VIM::evaluate('copy(g:plugs)')
limit = VIM::evaluate('get(g:, "plug_timeout", 60)')
done = {} done = {}
skip = 'Already installed' skip = 'Already installed'
mtx = Mutex.new mtx = Mutex.new
@ -355,13 +358,23 @@ function! s:update_parallel(pull, threads)
logh.call logh.call
end end
} }
bt = iswin ? proc { |cmd| bt = proc { |cmd|
begin
Timeout::timeout(limit) do
if iswin
tmp = VIM::evaluate('tempname()') tmp = VIM::evaluate('tempname()')
system("#{cmd} > #{tmp}") system("#{cmd} > #{tmp}")
data = File.read(tmp).chomp data = File.read(tmp).chomp
File.unlink tmp rescue nil File.unlink tmp rescue nil
data else
} : proc { |cmd| `#{cmd}`.chomp } data = `#{cmd}`.chomp
end
[$? == 0, data]
end
rescue Timeout::Error
[false, "Timeout!"]
end
}
until all.empty? until all.empty?
names = all.keys names = all.keys
@ -372,22 +385,21 @@ function! s:update_parallel(pull, threads)
dir, uri, branch = pair.last.values_at *%w[dir uri branch] dir, uri, branch = pair.last.values_at *%w[dir uri branch]
ok, result = ok, result =
if File.directory? dir if File.directory? dir
current_uri = bt.call "#{cd} #{dir} && git config remote.origin.url" ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url"
if $? == 0 && current_uri == uri current_uri = data.lines.to_a.last
if ret && current_uri == uri
if pull if pull
output = bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && git pull origin #{branch} 2>&1" bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && git pull origin #{branch} 2>&1"
[$? == 0, output]
else else
[true, skip] [true, skip]
end end
else else
[false, "PlugClean required. Invalid remote."] [false, "PlugClean required. Invalid status."]
end end
else else
FileUtils.mkdir_p(base) FileUtils.mkdir_p(base)
d = dir.sub(%r{[\\/]+$}, '') d = dir.sub(%r{[\\/]+$}, '')
r = bt.call "#{cd} #{base} && git clone --recursive #{uri} -b #{branch} #{d} 2>&1" bt.call "#{cd} #{base} && git clone --recursive #{uri} -b #{branch} #{d} 2>&1"
[$? == 0, r]
end end
result = result.lines.to_a.last result = result.lines.to_a.last
log.call name, (result && result.strip), ok log.call name, (result && result.strip), ok
@ -424,14 +436,31 @@ function! s:progress_bar(line, cnt, total)
endfunction endfunction
function! s:git_valid(spec, cd) function! s:git_valid(spec, cd)
let ret = 1
let msg = 'OK'
if isdirectory(a:spec.dir) if isdirectory(a:spec.dir)
if a:cd | execute "cd " . a:spec.dir | endif if a:cd | execute "cd " . a:spec.dir | endif
let ret = s:system("git config remote.origin.url") == a:spec.uri let remote = s:system("git config remote.origin.url")
if a:cd | cd - | endif
if remote != a:spec.uri
let msg = 'Invalid remote: ' . remote . '. Try PlugClean.'
let ret = 0
else else
let branch = s:system('git rev-parse --abbrev-ref HEAD')
if v:shell_error != 0
let msg = 'Invalid git repository. Try PlugClean.'
let ret = 0
elseif a:spec.branch != branch
let msg = 'Invalid branch: '.branch.'. Try PlugUpdate.'
let ret = 0 let ret = 0
endif endif
return ret endif
if a:cd | cd - | endif
else
let msg = 'Not found'
let ret = 0
endif
return [ret, msg]
endfunction endfunction
function! s:clean(force) function! s:clean(force)
@ -443,7 +472,7 @@ function! s:clean(force)
let dirs = [] let dirs = []
let [cnt, total] = [0, len(g:plugs)] let [cnt, total] = [0, len(g:plugs)]
for spec in values(g:plugs) for spec in values(g:plugs)
if s:git_valid(spec, 1) if s:git_valid(spec, 1)[0]
call add(dirs, spec.dir) call add(dirs, spec.dir)
endif endif
let cnt += 1 let cnt += 1
@ -525,13 +554,9 @@ function! s:status()
let err = 'OK' let err = 'OK'
if isdirectory(spec.dir) if isdirectory(spec.dir)
execute 'cd '.spec.dir execute 'cd '.spec.dir
if s:git_valid(spec, 0) let [valid, msg] = s:git_valid(spec, 0)
let branch = s:system('git rev-parse --abbrev-ref HEAD') if !valid
if spec.branch != branch let err = '(x) '. msg
let err = '(x) Invalid branch: '.branch.'. Try PlugUpdate.'
endif
else
let err = '(x) Invalid remote. Try PlugClean.'
endif endif
cd - cd -
else else