Ver Fonte

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.
Junegunn Choi há 12 anos atrás
pai
commit
fe942d61d2
2 ficheiros alterados com 57 adições e 27 exclusões
  1. 6 1
      README.md
  2. 51 26
      plug.vim

+ 6 - 1
README.md

@@ -65,7 +65,12 @@ plugins with `plug#begin(path)` call.
 | PlugUpgrade            | Upgrade vim-plug itself                                            |
 | 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
 

+ 51 - 26
plug.vim

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