Real-time progress report

This commit is almost identical to the reverted
60b907c87f, but it tries to avoid high CPU load
by not printing every line.
This commit is contained in:
Junegunn Choi 2014-07-13 03:54:53 +09:00
parent 35c5f2830b
commit af89938633
2 changed files with 84 additions and 24 deletions

106
plug.vim
View file

@ -323,7 +323,11 @@ function! s:syntax()
syn match plugBracket /[[\]]/ contained syn match plugBracket /[[\]]/ contained
syn match plugX /x/ contained syn match plugX /x/ contained
syn match plugDash /^-/ syn match plugDash /^-/
syn match plugPlus /^+/
syn match plugStar /^*/
syn match plugName /\(^- \)\@<=[^:]*/ syn match plugName /\(^- \)\@<=[^:]*/
syn match plugInstall /\(^+ \)\@<=[^:]*/
syn match plugUpdate /\(^* \)\@<=[^:]*/
syn match plugCommit /^ [0-9a-z]\{7} .*/ contains=plugRelDate,plugSha syn match plugCommit /^ [0-9a-z]\{7} .*/ contains=plugRelDate,plugSha
syn match plugSha /\(^ \)\@<=[0-9a-z]\{7}/ contained syn match plugSha /\(^ \)\@<=[0-9a-z]\{7}/ contained
syn match plugRelDate /([^)]*)$/ contained syn match plugRelDate /([^)]*)$/ contained
@ -334,8 +338,15 @@ function! s:syntax()
hi def link plugX Exception hi def link plugX Exception
hi def link plugBracket Structure hi def link plugBracket Structure
hi def link plugNumber Number hi def link plugNumber Number
hi def link plugDash Special hi def link plugDash Special
hi def link plugPlus Constant
hi def link plugStar Boolean
hi def link plugName Label hi def link plugName Label
hi def link plugInstall Function
hi def link plugUpdate Type
hi def link plugError Error hi def link plugError Error
hi def link plugRelDate Comment hi def link plugRelDate Comment
hi def link plugSha Identifier hi def link plugSha Identifier
@ -429,7 +440,21 @@ function! s:update_impl(pull, args) abort
let len = len(g:plugs) let len = len(g:plugs)
if has('ruby') && threads > 1 if has('ruby') && threads > 1
call s:update_parallel(a:pull, todo, threads) try
call s:update_parallel(a:pull, todo, threads)
catch
let lines = getline(4, '$')
let printed = {}
silent 4,$d
for line in lines
let name = get(matchlist(line, '^. \([^:]\+\):'), 1, '')
if empty(name) || !has_key(printed, name)
let printed[name] = 1
call append('$', line)
endif
endfor
echoerr v:exception
endtry
else else
call s:update_serial(a:pull, todo) call s:update_serial(a:pull, todo)
endif endif
@ -491,7 +516,6 @@ function! s:update_serial(pull, todo)
if !isdirectory(base) if !isdirectory(base)
call mkdir(base, 'p') call mkdir(base, 'p')
endif endif
execute 'cd '.base
let result = s:system( let result = s:system(
\ printf('git clone --recursive %s -b %s %s 2>&1 && cd %s && git submodule update --init --recursive 2>&1', \ printf('git clone --recursive %s -b %s %s 2>&1 && cd %s && git submodule update --init --recursive 2>&1',
\ s:shellesc(spec.uri), \ s:shellesc(spec.uri),
@ -520,6 +544,23 @@ endfunction
function! s:update_parallel(pull, todo, threads) function! s:update_parallel(pull, todo, threads)
ruby << EOF ruby << EOF
module PlugStream
SEP = ["\r", "\n", nil]
def get_line
buffer = ''
loop do
char = readchar rescue return
if SEP.include? char
buffer << $/
break
else
buffer << char
end
end
buffer
end
end unless defined?(PlugStream)
def esc arg def esc arg
%["#{arg.gsub('"', '\"')}"] %["#{arg.gsub('"', '\"')}"]
end end
@ -535,55 +576,70 @@ function! s:update_parallel(pull, todo, threads)
all = VIM::evaluate('copy(a:todo)') all = VIM::evaluate('copy(a:todo)')
limit = VIM::evaluate('get(g:, "plug_timeout", 60)') limit = VIM::evaluate('get(g:, "plug_timeout", 60)')
nthr = VIM::evaluate('a:threads').to_i nthr = VIM::evaluate('a:threads').to_i
maxy = VIM::evaluate('winheight(".")').to_i
cd = iswin ? 'cd /d' : 'cd' cd = iswin ? 'cd /d' : 'cd'
done = {}
tot = 0 tot = 0
bar = '' bar = ''
skip = 'Already installed' skip = 'Already installed'
mtx = Mutex.new mtx = Mutex.new
take1 = proc { mtx.synchronize { running && all.shift } } take1 = proc { mtx.synchronize { running && all.shift } }
logh = proc { logh = proc {
cnt = done.length cnt = $curbuf[2][1...-1].strip.length
tot = VIM::evaluate('len(a:todo)') || tot tot = VIM::evaluate('len(a:todo)') || tot
$curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})"
$curbuf[2] = '[' + bar.ljust(tot) + ']' $curbuf[2] = '[' + bar.ljust(tot) + ']'
VIM::command('normal! 2G') VIM::command('normal! 2G')
VIM::command('redraw') unless iswin VIM::command('redraw') unless iswin
} }
log = proc { |name, result, ok| where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } }
log = proc { |name, result, type|
mtx.synchronize do mtx.synchronize do
bar += ok ? '=' : 'x' ing = ![true, false].include?(type)
done[name] = true bar += type ? '=' : 'x' unless ing
b = case type
when :install then '+' when :update then '*'
when true, nil then '-' else 'x' end
result = result =
if ok if type || type.nil?
["- #{name}: #{result.lines.to_a.last.strip}"] ["#{b} #{name}: #{result.lines.to_a.last}"]
elsif result =~ /^Interrupted|^Timeout/ elsif result =~ /^Interrupted|^Timeout/
["x #{name}: #{result}"] ["#{b} #{name}: #{result}"]
else else
["x #{name}"] + result.lines.map { |l| " " << l } ["#{b} #{name}"] + result.lines.map { |l| " " << l }
end end
if lnum = where.call(name)
$curbuf.delete lnum
lnum = 4 if ing && lnum > maxy
end
result.each_with_index do |line, offset| result.each_with_index do |line, offset|
$curbuf.append 3 + offset, line.chomp $curbuf.append (lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp
end end
logh.call logh.call
end end
} }
bt = proc { |cmd| bt = proc { |cmd, name, type|
begin begin
fd = nil fd = nil
Timeout::timeout(limit) do data = ''
if iswin if iswin
Timeout::timeout(limit) do
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
else
fd = IO.popen(cmd)
data = fd.read.chomp
fd.close
end end
[$? == 0, data] else
fd = IO.popen(cmd).extend(PlugStream)
first_line = true
log_prob = 1.0 / nthr
while line = Timeout::timeout(limit) { fd.get_line }
data << line
log.call name, line.chomp, type if name && (first_line || rand < log_prob)
first_line = false
end
fd.close
end end
[$? == 0, data.chomp]
rescue Timeout::Error, Interrupt => e rescue Timeout::Error, Interrupt => e
if fd && !fd.closed? if fd && !fd.closed?
pids = [fd.pid] pids = [fd.pid]
@ -616,6 +672,7 @@ function! s:update_parallel(pull, todo, threads)
main.kill main.kill
} }
progress = iswin ? '' : '--progress'
until all.empty? until all.empty?
names = all.keys names = all.keys
[names.length, nthr].min.times do [names.length, nthr].min.times do
@ -625,10 +682,11 @@ function! s:update_parallel(pull, todo, threads)
name = pair.first name = pair.first
dir, uri, branch = pair.last.values_at *%w[dir uri branch] dir, uri, branch = pair.last.values_at *%w[dir uri branch]
branch = esc branch branch = esc branch
subm = "git submodule update --init --recursive 2>&1"
ok, result = ok, result =
if File.directory? dir if File.directory? dir
dir = esc dir dir = esc dir
ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url" ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil
current_uri = data.lines.to_a.last current_uri = data.lines.to_a.last
if !ret if !ret
if data =~ /^Interrupted|^Timeout/ if data =~ /^Interrupted|^Timeout/
@ -642,7 +700,8 @@ function! s:update_parallel(pull, todo, threads)
"PlugClean required."].join($/)] "PlugClean required."].join($/)]
else else
if pull if pull
bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && git pull origin #{branch} 2>&1 && git submodule update --init --recursive 2>&1" log.call name, 'Updating ...', :update
bt.call "#{cd} #{dir} && git checkout -q #{branch} 2>&1 && (git pull origin #{branch} #{progress} 2>&1 && #{subm})", name, :update
else else
[true, skip] [true, skip]
end end
@ -650,7 +709,8 @@ function! s:update_parallel(pull, todo, threads)
else else
FileUtils.mkdir_p(base) FileUtils.mkdir_p(base)
d = esc dir.sub(%r{[\\/]+$}, '') d = esc dir.sub(%r{[\\/]+$}, '')
bt.call "#{cd} #{base} && git clone --recursive #{uri} -b #{branch} #{d} 2>&1 && cd #{esc dir} && git submodule update --init --recursive 2>&1" log.call name, 'Installing ...', :install
bt.call "(git clone #{progress} --recursive #{uri} -b #{branch} #{d} 2>&1 && cd #{esc dir} && #{subm})", name, :install
end end
log.call name, result, ok log.call name, result, ok
end end

View file

@ -239,7 +239,7 @@ Execute (PlugClean! to remove vim-emoji):
Execute (PlugUpdate to install both again): Execute (PlugUpdate to install both again):
PlugUpdate PlugUpdate
AssertEqual 2, len(filter(getline(1, line('$')), 'v:val =~ "Cloning into"')) AssertEqual 2, len(filter(getline(1, line('$')), 'v:val =~ "^- [^:]*:"'))
AssertEqual 3, g:vimrc_reloaded AssertEqual 3, g:vimrc_reloaded
Assert !empty(globpath(&rtp, 'colors/seoul256.vim')), 'seoul256.vim should be found' Assert !empty(globpath(&rtp, 'colors/seoul256.vim')), 'seoul256.vim should be found'
Assert !empty(globpath(&rtp, 'autoload/emoji.vim')), 'vim-emoji should be found' Assert !empty(globpath(&rtp, 'autoload/emoji.vim')), 'vim-emoji should be found'