Mercurial > dotfiles.old
comparison vim/autoload/plug.vim @ 247:5199030e3e2c
Update vimplug
author | zegervdv <zegervdv@me.com> |
---|---|
date | Sun, 22 Feb 2015 22:38:06 +0100 |
parents | 0994a5f99432 |
children | f0d3b37101c0 |
comparison
equal
deleted
inserted
replaced
246:624d06dcf54c | 247:5199030e3e2c |
---|---|
71 let s:plug_src = 'https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim' | 71 let s:plug_src = 'https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim' |
72 let s:plug_tab = get(s:, 'plug_tab', -1) | 72 let s:plug_tab = get(s:, 'plug_tab', -1) |
73 let s:plug_buf = get(s:, 'plug_buf', -1) | 73 let s:plug_buf = get(s:, 'plug_buf', -1) |
74 let s:mac_gui = has('gui_macvim') && has('gui_running') | 74 let s:mac_gui = has('gui_macvim') && has('gui_running') |
75 let s:is_win = has('win32') || has('win64') | 75 let s:is_win = has('win32') || has('win64') |
76 let s:py2 = has('python') && !s:is_win | |
76 let s:ruby = has('ruby') && (v:version >= 703 || v:version == 702 && has('patch374')) | 77 let s:ruby = has('ruby') && (v:version >= 703 || v:version == 702 && has('patch374')) |
77 let s:nvim = has('nvim') && !s:is_win | 78 let s:nvim = has('nvim') && !s:is_win |
78 let s:me = resolve(expand('<sfile>:p')) | 79 let s:me = resolve(expand('<sfile>:p')) |
79 let s:base_spec = { 'branch': 'master', 'frozen': 0 } | 80 let s:base_spec = { 'branch': 'master', 'frozen': 0 } |
80 let s:TYPE = { | 81 let s:TYPE = { |
233 | 234 |
234 function! s:trim(str) | 235 function! s:trim(str) |
235 return substitute(a:str, '[\/]\+$', '', '') | 236 return substitute(a:str, '[\/]\+$', '', '') |
236 endfunction | 237 endfunction |
237 | 238 |
239 function! s:version_requirement(val, min) | |
240 for idx in range(0, len(a:min) - 1) | |
241 let v = get(a:val, idx, 0) | |
242 if v < a:min[idx] | return 0 | |
243 elseif v > a:min[idx] | return 1 | |
244 endif | |
245 endfor | |
246 return 1 | |
247 endfunction | |
248 | |
238 function! s:git_version_requirement(...) | 249 function! s:git_version_requirement(...) |
239 let s:git_version = get(s:, 'git_version', | 250 let s:git_version = get(s:, 'git_version', |
240 \ map(split(split(s:system('git --version'))[-1], '\.'), 'str2nr(v:val)')) | 251 \ map(split(split(s:system('git --version'))[-1], '\.'), 'str2nr(v:val)')) |
241 for idx in range(0, a:0 - 1) | 252 return s:version_requirement(s:git_version, a:000) |
242 let v = get(s:git_version, idx, 0) | |
243 if v < a:000[idx] | return 0 | |
244 elseif v > a:000[idx] | return 1 | |
245 endif | |
246 endfor | |
247 return 1 | |
248 endfunction | 253 endfunction |
249 | 254 |
250 function! s:progress_opt(base) | 255 function! s:progress_opt(base) |
251 return a:base && !s:is_win && | 256 return a:base && !s:is_win && |
252 \ s:git_version_requirement(1, 7, 1) ? '--progress' : '' | 257 \ s:git_version_requirement(1, 7, 1) ? '--progress' : '' |
432 | 437 |
433 function! s:parse_options(arg) | 438 function! s:parse_options(arg) |
434 let opts = copy(s:base_spec) | 439 let opts = copy(s:base_spec) |
435 let type = type(a:arg) | 440 let type = type(a:arg) |
436 if type == s:TYPE.string | 441 if type == s:TYPE.string |
437 let opts.branch = a:arg | 442 let opts.tag = a:arg |
438 elseif type == s:TYPE.dict | 443 elseif type == s:TYPE.dict |
439 call extend(opts, a:arg) | 444 call extend(opts, a:arg) |
440 if has_key(opts, 'tag') | |
441 let opts.branch = remove(opts, 'tag') | |
442 endif | |
443 if has_key(opts, 'dir') | 445 if has_key(opts, 'dir') |
444 let opts.dir = s:dirpath(expand(opts.dir)) | 446 let opts.dir = s:dirpath(expand(opts.dir)) |
445 endif | 447 endif |
446 else | 448 else |
447 throw 'Invalid argument type (expected: string or dictionary)' | 449 throw 'Invalid argument type (expected: string or dictionary)' |
604 let s:plug_buf = winbufnr(0) | 606 let s:plug_buf = winbufnr(0) |
605 call s:assign_name() | 607 call s:assign_name() |
606 endif | 608 endif |
607 silent! unmap <buffer> <cr> | 609 silent! unmap <buffer> <cr> |
608 silent! unmap <buffer> L | 610 silent! unmap <buffer> L |
611 silent! unmap <buffer> o | |
609 silent! unmap <buffer> X | 612 silent! unmap <buffer> X |
610 setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap cursorline modifiable | 613 setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap cursorline modifiable |
611 setf vim-plug | 614 setf vim-plug |
612 call s:syntax() | 615 call s:syntax() |
613 endfunction | 616 endfunction |
742 \ 'todo': copy(todo), | 745 \ 'todo': copy(todo), |
743 \ 'errors': [], | 746 \ 'errors': [], |
744 \ 'pull': a:pull, | 747 \ 'pull': a:pull, |
745 \ 'force': a:force, | 748 \ 'force': a:force, |
746 \ 'new': {}, | 749 \ 'new': {}, |
747 \ 'threads': (s:ruby || s:nvim) ? min([len(todo), threads]) : 1, | 750 \ 'threads': (s:py2 || s:ruby || s:nvim) ? min([len(todo), threads]) : 1, |
748 \ 'bar': '', | 751 \ 'bar': '', |
749 \ 'fin': 0 | 752 \ 'fin': 0 |
750 \ } | 753 \ } |
751 | 754 |
752 call s:prepare() | 755 call s:prepare() |
753 call append(0, ['', '']) | 756 call append(0, ['', '']) |
754 normal! 2G | 757 normal! 2G |
755 | 758 |
756 if s:ruby && s:update.threads > 1 | 759 " Python version requirement (>= 2.7) |
760 if s:py2 && !s:ruby && !s:nvim && s:update.threads > 1 | |
761 redir => pyv | |
762 silent python import platform; print(platform.python_version()) | |
763 redir END | |
764 let s:py2 = s:version_requirement( | |
765 \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 7]) | |
766 endif | |
767 if (s:py2 || s:ruby) && !s:nvim && s:update.threads > 1 | |
757 try | 768 try |
758 let imd = &imd | 769 let imd = &imd |
759 if s:mac_gui | 770 if s:mac_gui |
760 set noimd | 771 set noimd |
761 endif | 772 endif |
762 call s:update_ruby() | 773 if s:ruby |
774 call s:update_ruby() | |
775 else | |
776 call s:update_python() | |
777 endif | |
763 catch | 778 catch |
764 let lines = getline(4, '$') | 779 let lines = getline(4, '$') |
765 let printed = {} | 780 let printed = {} |
766 silent! 4,$d _ | 781 silent! 4,$d _ |
767 for line in lines | 782 for line in lines |
947 let new = !isdirectory(spec.dir) | 962 let new = !isdirectory(spec.dir) |
948 | 963 |
949 call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...') | 964 call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...') |
950 redraw | 965 redraw |
951 | 966 |
967 let checkout = s:shellesc(has_key(spec, 'tag') ? spec.tag : spec.branch) | |
968 let merge = s:shellesc(has_key(spec, 'tag') ? spec.tag : 'origin/'.spec.branch) | |
969 | |
952 if !new | 970 if !new |
953 let [valid, msg] = s:git_valid(spec, 0) | 971 let [valid, msg] = s:git_valid(spec, 0) |
954 if valid | 972 if valid |
955 if pull | 973 if pull |
956 call s:spawn(name, | 974 call s:spawn(name, |
957 \ printf('(git fetch %s 2>&1 && git checkout -q %s 2>&1 && git merge --ff-only origin/%s 2>&1 && git submodule update --init --recursive 2>&1)', | 975 \ printf('(git fetch %s 2>&1 && git checkout -q %s 2>&1 && git merge --ff-only %s 2>&1 && git submodule update --init --recursive 2>&1)', |
958 \ prog, s:shellesc(spec.branch), s:shellesc(spec.branch)), { 'dir': spec.dir }) | 976 \ prog, checkout, merge), { 'dir': spec.dir }) |
959 else | 977 else |
960 let s:jobs[name] = { 'running': 0, 'result': 'Already installed', 'error': 0 } | 978 let s:jobs[name] = { 'running': 0, 'result': 'Already installed', 'error': 0 } |
961 endif | 979 endif |
962 else | 980 else |
963 let s:jobs[name] = { 'running': 0, 'result': msg, 'error': 1 } | 981 let s:jobs[name] = { 'running': 0, 'result': msg, 'error': 1 } |
965 else | 983 else |
966 call s:spawn(name, | 984 call s:spawn(name, |
967 \ printf('git clone %s --recursive %s -b %s %s 2>&1', | 985 \ printf('git clone %s --recursive %s -b %s %s 2>&1', |
968 \ prog, | 986 \ prog, |
969 \ s:shellesc(spec.uri), | 987 \ s:shellesc(spec.uri), |
970 \ s:shellesc(spec.branch), | 988 \ checkout, |
971 \ s:shellesc(s:trim(spec.dir))), { 'new': 1 }) | 989 \ s:shellesc(s:trim(spec.dir))), { 'new': 1 }) |
972 endif | 990 endif |
973 | 991 |
974 if !s:jobs[name].running | 992 if !s:jobs[name].running |
975 call s:reap(name) | 993 call s:reap(name) |
976 endif | 994 endif |
977 if len(s:jobs) >= s:update.threads | 995 if len(s:jobs) >= s:update.threads |
978 break | 996 break |
979 endif | 997 endif |
980 endwhile | 998 endwhile |
999 endfunction | |
1000 | |
1001 function! s:update_python() | |
1002 python << EOF | |
1003 """ Due to use of signals this function is POSIX only. """ | |
1004 import datetime | |
1005 import functools | |
1006 import os | |
1007 import Queue | |
1008 import random | |
1009 import re | |
1010 import shutil | |
1011 import signal | |
1012 import subprocess | |
1013 import tempfile | |
1014 import threading as thr | |
1015 import time | |
1016 import traceback | |
1017 import vim | |
1018 | |
1019 G_PULL = vim.eval('s:update.pull') == '1' | |
1020 G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1 | |
1021 G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)')) | |
1022 G_PROGRESS = vim.eval('s:progress_opt(1)') | |
1023 G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads')) | |
1024 G_STOP = thr.Event() | |
1025 | |
1026 class CmdTimedOut(Exception): | |
1027 pass | |
1028 class CmdFailed(Exception): | |
1029 pass | |
1030 class InvalidURI(Exception): | |
1031 pass | |
1032 class Action(object): | |
1033 INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-'] | |
1034 | |
1035 class GLog(object): | |
1036 ON = None | |
1037 LOGDIR = None | |
1038 @classmethod | |
1039 def write(cls, msg): | |
1040 if cls.ON is None: | |
1041 cls.ON = int(vim.eval('get(g:, "plug_log_on", 0)')) | |
1042 cls.LOGDIR = os.path.expanduser(vim.eval('get(g:, "plug_logs", "~/plug_logs")')) | |
1043 if cls.ON: | |
1044 if not os.path.exists(cls.LOGDIR): | |
1045 os.makedirs(cls.LOGDIR) | |
1046 cls._write(msg) | |
1047 @classmethod | |
1048 def _write(cls, msg): | |
1049 name = thr.current_thread().name | |
1050 fname = cls.LOGDIR + os.path.sep + name | |
1051 with open(fname, 'ab') as flog: | |
1052 ltime = datetime.datetime.now().strftime("%H:%M:%S.%f") | |
1053 msg = '[{},{}] {}{}'.format(name, ltime, msg, '\n') | |
1054 flog.write(msg) | |
1055 | |
1056 class Buffer(object): | |
1057 def __init__(self, lock, num_plugs): | |
1058 self.bar = '' | |
1059 self.event = 'Updating' if vim.eval('s:update.pull') == '1' else 'Installing' | |
1060 self.is_win = vim.eval('s:is_win') == '1' | |
1061 self.lock = lock | |
1062 self.maxy = int(vim.eval('winheight(".")')) | |
1063 self.num_plugs = num_plugs | |
1064 | |
1065 def _where(self, name): | |
1066 """ Find first line with name in current buffer. Return line num. """ | |
1067 found, lnum = False, 0 | |
1068 matcher = re.compile('^[-+x*] {}:'.format(name)) | |
1069 for line in vim.current.buffer: | |
1070 if matcher.search(line) is not None: | |
1071 found = True | |
1072 break | |
1073 lnum += 1 | |
1074 | |
1075 if not found: | |
1076 lnum = -1 | |
1077 return lnum | |
1078 | |
1079 def header(self): | |
1080 curbuf = vim.current.buffer | |
1081 curbuf[0] = self.event + ' plugins ({}/{})'.format(len(self.bar), self.num_plugs) | |
1082 | |
1083 num_spaces = self.num_plugs - len(self.bar) | |
1084 curbuf[1] = '[{}{}]'.format(self.bar, num_spaces * ' ') | |
1085 | |
1086 vim.command('normal! 2G') | |
1087 if not self.is_win: | |
1088 vim.command('redraw') | |
1089 | |
1090 def write(self, *args, **kwargs): | |
1091 with self.lock: | |
1092 self._write(*args, **kwargs) | |
1093 | |
1094 def _write(self, action, name, lines): | |
1095 first, rest = lines[0], lines[1:] | |
1096 msg = ['{} {}{}{}'.format(action, name, ': ' if first else '', first)] | |
1097 padded_rest = [' ' + line for line in rest] | |
1098 msg.extend(padded_rest) | |
1099 | |
1100 try: | |
1101 if action == Action.ERROR: | |
1102 self.bar += 'x' | |
1103 vim.command("call add(s:update.errors, '{}')".format(name)) | |
1104 elif action == Action.DONE: | |
1105 self.bar += '=' | |
1106 | |
1107 curbuf = vim.current.buffer | |
1108 lnum = self._where(name) | |
1109 if lnum != -1: # Found matching line num | |
1110 del curbuf[lnum] | |
1111 if lnum > self.maxy and action in {Action.INSTALL, Action.UPDATE}: | |
1112 lnum = 3 | |
1113 else: | |
1114 lnum = 3 | |
1115 curbuf.append(msg, lnum) | |
1116 | |
1117 self.header() | |
1118 except vim.error: | |
1119 GLog.write('Buffer Update FAILED.') | |
1120 | |
1121 class Command(object): | |
1122 def __init__(self, cmd, cmd_dir=None, timeout=60, ntries=3, cb=None, clean=None): | |
1123 self.cmd = cmd | |
1124 self.cmd_dir = cmd_dir | |
1125 self.timeout = timeout | |
1126 self.ntries = ntries | |
1127 self.callback = cb if cb else (lambda msg: None) | |
1128 self.clean = clean | |
1129 | |
1130 def attempt_cmd(self): | |
1131 """ Tries to run the command, returns result if no exceptions. """ | |
1132 attempt = 0 | |
1133 finished = False | |
1134 limit = self.timeout | |
1135 | |
1136 while not finished: | |
1137 try: | |
1138 attempt += 1 | |
1139 result = self.timeout_cmd() | |
1140 finished = True | |
1141 except CmdTimedOut: | |
1142 if attempt != self.ntries: | |
1143 for count in range(3, 0, -1): | |
1144 if G_STOP.is_set(): | |
1145 raise KeyboardInterrupt | |
1146 msg = 'Timeout. Will retry in {} second{} ...'.format( | |
1147 count, 's' if count != 1 else '') | |
1148 self.callback([msg]) | |
1149 time.sleep(1) | |
1150 self.timeout += limit | |
1151 self.callback(['Retrying ...']) | |
1152 else: | |
1153 raise | |
1154 | |
1155 return result | |
1156 | |
1157 def timeout_cmd(self): | |
1158 """ Execute a cmd & poll for callback. Returns list of output. | |
1159 Raises CmdFailed -> return code for Popen isn't 0 | |
1160 Raises CmdTimedOut -> command exceeded timeout without new output | |
1161 """ | |
1162 proc = None | |
1163 first_line = True | |
1164 try: | |
1165 tfile = tempfile.NamedTemporaryFile() | |
1166 proc = subprocess.Popen(self.cmd, cwd=self.cmd_dir, stdout=tfile, | |
1167 stderr=subprocess.STDOUT, shell=True, preexec_fn=os.setsid) | |
1168 while proc.poll() is None: | |
1169 # Yield this thread | |
1170 time.sleep(0.2) | |
1171 | |
1172 if G_STOP.is_set(): | |
1173 raise KeyboardInterrupt | |
1174 | |
1175 if first_line or random.random() < G_LOG_PROB: | |
1176 first_line = False | |
1177 line = nonblock_read(tfile.name) | |
1178 if line: | |
1179 self.callback([line]) | |
1180 | |
1181 time_diff = time.time() - os.path.getmtime(tfile.name) | |
1182 if time_diff > self.timeout: | |
1183 raise CmdTimedOut(['Timeout!']) | |
1184 | |
1185 tfile.seek(0) | |
1186 result = [line.rstrip() for line in tfile] | |
1187 | |
1188 if proc.returncode != 0: | |
1189 msg = [''] | |
1190 msg.extend(result) | |
1191 raise CmdFailed(msg) | |
1192 except: | |
1193 if proc and proc.poll() is None: | |
1194 os.killpg(proc.pid, signal.SIGTERM) | |
1195 if self.clean: | |
1196 self.clean() | |
1197 raise | |
1198 | |
1199 return result | |
1200 | |
1201 class Plugin(object): | |
1202 def __init__(self, name, args, buf, lock): | |
1203 self.name = name | |
1204 self.args = args | |
1205 self.buf = buf | |
1206 self.lock = lock | |
1207 tag = args.get('tag', 0) | |
1208 self.checkout = esc(tag if tag else args['branch']) | |
1209 self.merge = esc(tag if tag else 'origin/' + args['branch']) | |
1210 | |
1211 def manage(self): | |
1212 try: | |
1213 if os.path.exists(self.args['dir']): | |
1214 self.update() | |
1215 else: | |
1216 self.install() | |
1217 with self.lock: | |
1218 vim.command("let s:update.new['{}'] = 1".format(self.name)) | |
1219 except (CmdTimedOut, CmdFailed, InvalidURI) as exc: | |
1220 self.write(Action.ERROR, self.name, exc.message) | |
1221 except KeyboardInterrupt: | |
1222 G_STOP.set() | |
1223 self.write(Action.ERROR, self.name, ['Interrupted!']) | |
1224 except: | |
1225 # Any exception except those above print stack trace | |
1226 msg = 'Trace:\n{}'.format(traceback.format_exc().rstrip()) | |
1227 self.write(Action.ERROR, self.name, msg.split('\n')) | |
1228 raise | |
1229 | |
1230 def install(self): | |
1231 target = self.args['dir'] | |
1232 | |
1233 def clean(target): | |
1234 def _clean(): | |
1235 try: | |
1236 shutil.rmtree(target) | |
1237 except OSError: | |
1238 pass | |
1239 return _clean | |
1240 | |
1241 self.write(Action.INSTALL, self.name, ['Installing ...']) | |
1242 callback = functools.partial(self.buf.write, Action.INSTALL, self.name) | |
1243 cmd = 'git clone {} --recursive {} -b {} {} 2>&1'.format( | |
1244 G_PROGRESS, self.args['uri'], self.checkout, esc(target)) | |
1245 com = Command(cmd, None, G_TIMEOUT, G_RETRIES, callback, clean(target)) | |
1246 result = com.attempt_cmd() | |
1247 self.write(Action.DONE, self.name, result[-1:]) | |
1248 | |
1249 def update(self): | |
1250 match = re.compile(r'git::?@') | |
1251 actual_uri = re.sub(match, '', self.repo_uri()) | |
1252 expect_uri = re.sub(match, '', self.args['uri']) | |
1253 if actual_uri != expect_uri: | |
1254 msg = ['', | |
1255 'Invalid URI: {}'.format(actual_uri), | |
1256 'Expected {}'.format(expect_uri), | |
1257 'PlugClean required.'] | |
1258 raise InvalidURI(msg) | |
1259 | |
1260 if G_PULL: | |
1261 self.write(Action.UPDATE, self.name, ['Updating ...']) | |
1262 callback = functools.partial(self.buf.write, Action.UPDATE, self.name) | |
1263 cmds = ['git fetch {}'.format(G_PROGRESS), | |
1264 'git checkout -q {}'.format(self.checkout), | |
1265 'git merge --ff-only {}'.format(self.merge), | |
1266 'git submodule update --init --recursive'] | |
1267 cmd = ' 2>&1 && '.join(cmds) | |
1268 GLog.write(cmd) | |
1269 com = Command(cmd, self.args['dir'], G_TIMEOUT, G_RETRIES, callback) | |
1270 result = com.attempt_cmd() | |
1271 GLog.write(result) | |
1272 self.write(Action.DONE, self.name, result[-1:]) | |
1273 else: | |
1274 self.write(Action.DONE, self.name, ['Already installed']) | |
1275 | |
1276 def repo_uri(self): | |
1277 cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url' | |
1278 command = Command(cmd, self.args['dir'], G_TIMEOUT, G_RETRIES) | |
1279 result = command.attempt_cmd() | |
1280 return result[-1] | |
1281 | |
1282 def write(self, action, name, msg): | |
1283 GLog.write('{} {}: {}'.format(action, name, '\n'.join(msg))) | |
1284 self.buf.write(action, name, msg) | |
1285 | |
1286 class PlugThread(thr.Thread): | |
1287 def __init__(self, tname, args): | |
1288 super(PlugThread, self).__init__() | |
1289 self.tname = tname | |
1290 self.args = args | |
1291 | |
1292 def run(self): | |
1293 thr.current_thread().name = self.tname | |
1294 work_q, lock, buf = self.args | |
1295 | |
1296 try: | |
1297 while not G_STOP.is_set(): | |
1298 name, args = work_q.get_nowait() | |
1299 GLog.write('{}: Dir {}'.format(name, args['dir'])) | |
1300 plug = Plugin(name, args, buf, lock) | |
1301 plug.manage() | |
1302 work_q.task_done() | |
1303 except Queue.Empty: | |
1304 GLog.write('Queue now empty.') | |
1305 | |
1306 class RefreshThread(thr.Thread): | |
1307 def __init__(self, lock): | |
1308 super(RefreshThread, self).__init__() | |
1309 self.lock = lock | |
1310 self.running = True | |
1311 | |
1312 def run(self): | |
1313 while self.running: | |
1314 with self.lock: | |
1315 vim.command('noautocmd normal! a') | |
1316 time.sleep(0.2) | |
1317 | |
1318 def stop(self): | |
1319 self.running = False | |
1320 | |
1321 def esc(name): | |
1322 return '"' + name.replace('"', '\"') + '"' | |
1323 | |
1324 def nonblock_read(fname): | |
1325 """ Read a file with nonblock flag. Return the last line. """ | |
1326 fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK) | |
1327 buf = os.read(fread, 100000) | |
1328 os.close(fread) | |
1329 | |
1330 line = buf.rstrip('\r\n') | |
1331 left = max(line.rfind('\r'), line.rfind('\n')) | |
1332 if left != -1: | |
1333 left += 1 | |
1334 line = line[left:] | |
1335 | |
1336 return line | |
1337 | |
1338 def main(): | |
1339 thr.current_thread().name = 'main' | |
1340 GLog.write('') | |
1341 if GLog.ON and os.path.exists(GLog.LOGDIR): | |
1342 shutil.rmtree(GLog.LOGDIR) | |
1343 | |
1344 threads = [] | |
1345 nthreads = int(vim.eval('s:update.threads')) | |
1346 plugs = vim.eval('s:update.todo') | |
1347 mac_gui = vim.eval('s:mac_gui') == '1' | |
1348 is_win = vim.eval('s:is_win') == '1' | |
1349 GLog.write('Plugs: {}'.format(plugs)) | |
1350 GLog.write('PULL: {}, WIN: {}, MAC: {}'.format(G_PULL, is_win, mac_gui)) | |
1351 GLog.write('Num Threads: {}'.format(nthreads)) | |
1352 | |
1353 lock = thr.Lock() | |
1354 buf = Buffer(lock, len(plugs)) | |
1355 work_q = Queue.Queue() | |
1356 for work in plugs.items(): | |
1357 work_q.put(work) | |
1358 | |
1359 GLog.write('Starting Threads') | |
1360 for num in range(nthreads): | |
1361 tname = 'PlugT-{0:02}'.format(num) | |
1362 thread = PlugThread(tname, (work_q, lock, buf)) | |
1363 thread.start() | |
1364 threads.append(thread) | |
1365 if mac_gui: | |
1366 rthread = RefreshThread(lock) | |
1367 rthread.start() | |
1368 | |
1369 GLog.write('Joining Live Threads') | |
1370 for thread in threads: | |
1371 thread.join() | |
1372 if mac_gui: | |
1373 rthread.stop() | |
1374 rthread.join() | |
1375 GLog.write('Cleanly Exited Main') | |
1376 | |
1377 main() | |
1378 EOF | |
981 endfunction | 1379 endfunction |
982 | 1380 |
983 function! s:update_ruby() | 1381 function! s:update_ruby() |
984 ruby << EOF | 1382 ruby << EOF |
985 module PlugStream | 1383 module PlugStream |
1079 fd = nil | 1477 fd = nil |
1080 data = '' | 1478 data = '' |
1081 if iswin | 1479 if iswin |
1082 Timeout::timeout(timeout) do | 1480 Timeout::timeout(timeout) do |
1083 tmp = VIM::evaluate('tempname()') | 1481 tmp = VIM::evaluate('tempname()') |
1084 system("#{cmd} > #{tmp}") | 1482 system("(#{cmd}) > #{tmp}") |
1085 data = File.read(tmp).chomp | 1483 data = File.read(tmp).chomp |
1086 File.unlink tmp rescue nil | 1484 File.unlink tmp rescue nil |
1087 end | 1485 end |
1088 else | 1486 else |
1089 fd = IO.popen(cmd).extend(PlugStream) | 1487 fd = IO.popen(cmd).extend(PlugStream) |
1142 nthr.times do | 1540 nthr.times do |
1143 mtx.synchronize do | 1541 mtx.synchronize do |
1144 threads << Thread.new { | 1542 threads << Thread.new { |
1145 while pair = take1.call | 1543 while pair = take1.call |
1146 name = pair.first | 1544 name = pair.first |
1147 dir, uri, branch = pair.last.values_at *%w[dir uri branch] | 1545 dir, uri, branch, tag = pair.last.values_at *%w[dir uri branch tag] |
1148 branch = esc branch | 1546 checkout = esc(tag ? tag : branch) |
1547 merge = esc(tag ? tag : "origin/#{branch}") | |
1149 subm = "git submodule update --init --recursive 2>&1" | 1548 subm = "git submodule update --init --recursive 2>&1" |
1150 exists = File.directory? dir | 1549 exists = File.directory? dir |
1151 ok, result = | 1550 ok, result = |
1152 if exists | 1551 if exists |
1153 dir = esc dir | 1552 dir = iswin ? dir : esc(dir) |
1154 ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil, nil | 1553 ret, data = bt.call "#{cd} #{dir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config remote.origin.url", nil, nil, nil |
1155 current_uri = data.lines.to_a.last | 1554 current_uri = data.lines.to_a.last |
1156 if !ret | 1555 if !ret |
1157 if data =~ /^Interrupted|^Timeout/ | 1556 if data =~ /^Interrupted|^Timeout/ |
1158 [false, data] | 1557 [false, data] |
1164 "Expected: #{uri}", | 1563 "Expected: #{uri}", |
1165 "PlugClean required."].join($/)] | 1564 "PlugClean required."].join($/)] |
1166 else | 1565 else |
1167 if pull | 1566 if pull |
1168 log.call name, 'Updating ...', :update | 1567 log.call name, 'Updating ...', :update |
1169 bt.call "#{cd} #{dir} && (git fetch #{progress} 2>&1 && git checkout -q #{branch} 2>&1 && git merge --ff-only origin/#{branch} 2>&1 && #{subm})", name, :update, nil | 1568 bt.call "#{cd} #{dir} && git fetch #{progress} 2>&1 && git checkout -q #{checkout} 2>&1 && git merge --ff-only #{merge} 2>&1 && #{subm}", name, :update, nil |
1170 else | 1569 else |
1171 [true, skip] | 1570 [true, skip] |
1172 end | 1571 end |
1173 end | 1572 end |
1174 else | 1573 else |
1175 d = esc dir.sub(%r{[\\/]+$}, '') | 1574 d = esc dir.sub(%r{[\\/]+$}, '') |
1176 log.call name, 'Installing ...', :install | 1575 log.call name, 'Installing ...', :install |
1177 bt.call "git clone #{progress} --recursive #{uri} -b #{branch} #{d} 2>&1", name, :install, proc { | 1576 bt.call "git clone #{progress} --recursive #{uri} -b #{checkout} #{d} 2>&1", name, :install, proc { |
1178 FileUtils.rm_rf dir | 1577 FileUtils.rm_rf dir |
1179 } | 1578 } |
1180 end | 1579 end |
1181 mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok | 1580 mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok |
1182 log.call name, result, ok | 1581 log.call name, result, ok |
1190 watcher.kill | 1589 watcher.kill |
1191 EOF | 1590 EOF |
1192 endfunction | 1591 endfunction |
1193 | 1592 |
1194 function! s:shellesc(arg) | 1593 function! s:shellesc(arg) |
1195 return '"'.substitute(a:arg, '"', '\\"', 'g').'"' | 1594 return '"'.escape(a:arg, '"').'"' |
1196 endfunction | 1595 endfunction |
1197 | 1596 |
1198 function! s:glob_dir(path) | 1597 function! s:glob_dir(path) |
1199 return map(filter(s:lines(globpath(a:path, '**')), 'isdirectory(v:val)'), 's:dirpath(v:val)') | 1598 return map(filter(s:lines(globpath(a:path, '**')), 'isdirectory(v:val)'), 's:dirpath(v:val)') |
1200 endfunction | 1599 endfunction |
1217 return extend([printf('x %s:', a:name)], lines) | 1616 return extend([printf('x %s:', a:name)], lines) |
1218 endif | 1617 endif |
1219 endfunction | 1618 endfunction |
1220 | 1619 |
1221 function! s:with_cd(cmd, dir) | 1620 function! s:with_cd(cmd, dir) |
1222 return (s:is_win ? 'cd /d ' : 'cd ').s:esc(a:dir).' && '.a:cmd | 1621 return printf('cd%s %s && %s', s:is_win ? ' /d' : '', s:shellesc(a:dir), a:cmd) |
1223 endfunction | 1622 endfunction |
1224 | 1623 |
1225 function! s:system(cmd, ...) | 1624 function! s:system(cmd, ...) |
1226 try | 1625 try |
1227 let sh = &shell | 1626 let sh = &shell |
1254 \ 'Expected: '.a:spec.uri, | 1653 \ 'Expected: '.a:spec.uri, |
1255 \ 'PlugClean required.'], "\n") | 1654 \ 'PlugClean required.'], "\n") |
1256 let ret = 0 | 1655 let ret = 0 |
1257 elseif a:check_branch | 1656 elseif a:check_branch |
1258 let branch = result[0] | 1657 let branch = result[0] |
1259 if a:spec.branch !=# branch | 1658 " Check tag |
1659 if has_key(a:spec, 'tag') | |
1260 let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir) | 1660 let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir) |
1261 if a:spec.branch !=# tag | 1661 if a:spec.tag !=# tag |
1262 let msg = printf('Invalid branch/tag: %s (expected: %s). Try PlugUpdate.', | 1662 let msg = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.', |
1263 \ (empty(tag) ? branch : tag), a:spec.branch) | 1663 \ (empty(tag) ? 'N/A' : tag), a:spec.tag) |
1264 let ret = 0 | 1664 let ret = 0 |
1265 endif | 1665 endif |
1666 " Check branch | |
1667 elseif a:spec.branch !=# branch | |
1668 let msg = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.', | |
1669 \ branch, a:spec.branch) | |
1670 let ret = 0 | |
1266 endif | 1671 endif |
1267 endif | 1672 endif |
1268 else | 1673 else |
1269 let msg = 'Not found' | 1674 let msg = 'Not found' |
1270 let ret = 0 | 1675 let ret = 0 |
1342 if v:shell_error | 1747 if v:shell_error |
1343 throw get(s:lines(output), -1, v:shell_error) | 1748 throw get(s:lines(output), -1, v:shell_error) |
1344 endif | 1749 endif |
1345 elseif s:ruby | 1750 elseif s:ruby |
1346 call s:upgrade_using_ruby(new) | 1751 call s:upgrade_using_ruby(new) |
1752 elseif s:py2 | |
1753 call s:upgrade_using_python(new) | |
1347 else | 1754 else |
1348 return s:err('curl executable or ruby support not found') | 1755 return s:err('Missing: curl executable, ruby support or python support') |
1349 endif | 1756 endif |
1350 catch | 1757 catch |
1351 return s:err('Error upgrading vim-plug: '. v:exception) | 1758 return s:err('Error upgrading vim-plug: '. v:exception) |
1352 endtry | 1759 endtry |
1353 | 1760 |
1368 ruby << EOF | 1775 ruby << EOF |
1369 require 'open-uri' | 1776 require 'open-uri' |
1370 File.open(VIM::evaluate('a:new'), 'w') do |f| | 1777 File.open(VIM::evaluate('a:new'), 'w') do |f| |
1371 f << open(VIM::evaluate('s:plug_src')).read | 1778 f << open(VIM::evaluate('s:plug_src')).read |
1372 end | 1779 end |
1780 EOF | |
1781 endfunction | |
1782 | |
1783 function! s:upgrade_using_python(new) | |
1784 python << EOF | |
1785 import urllib | |
1786 import vim | |
1787 psrc, dest = vim.eval('s:plug_src'), vim.eval('a:new') | |
1788 urllib.urlretrieve(psrc, dest) | |
1373 EOF | 1789 EOF |
1374 endfunction | 1790 endfunction |
1375 | 1791 |
1376 function! s:upgrade_specs() | 1792 function! s:upgrade_specs() |
1377 for spec in values(g:plugs) | 1793 for spec in values(g:plugs) |
1486 endif | 1902 endif |
1487 | 1903 |
1488 execute 'pedit' sha | 1904 execute 'pedit' sha |
1489 wincmd P | 1905 wincmd P |
1490 setlocal filetype=git buftype=nofile nobuflisted | 1906 setlocal filetype=git buftype=nofile nobuflisted |
1491 execute 'silent read !cd' s:esc(g:plugs[name].dir) '&& git show' sha | 1907 execute 'silent read !cd' s:shellesc(g:plugs[name].dir) '&& git show' sha |
1492 normal! gg"_dd | 1908 normal! gg"_dd |
1493 wincmd p | 1909 wincmd p |
1494 endfunction | 1910 endfunction |
1495 | 1911 |
1496 function! s:section(flags) | 1912 function! s:section(flags) |
1520 endif | 1936 endif |
1521 endfor | 1937 endfor |
1522 | 1938 |
1523 call setline(1, cnt == 0 ? 'No updates.' : 'Last update:') | 1939 call setline(1, cnt == 0 ? 'No updates.' : 'Last update:') |
1524 nnoremap <silent> <buffer> <cr> :silent! call <SID>preview_commit()<cr> | 1940 nnoremap <silent> <buffer> <cr> :silent! call <SID>preview_commit()<cr> |
1941 nnoremap <silent> <buffer> o :silent! call <SID>preview_commit()<cr> | |
1525 nnoremap <silent> <buffer> X :call <SID>revert()<cr> | 1942 nnoremap <silent> <buffer> X :call <SID>revert()<cr> |
1526 normal! gg | 1943 normal! gg |
1527 setlocal nomodifiable | 1944 setlocal nomodifiable |
1528 if cnt > 0 | 1945 if cnt > 0 |
1529 echo "Press 'X' on each block to revert the update" | 1946 echo "Press 'X' on each block to revert the update" |
1547 function! s:snapshot(...) abort | 1964 function! s:snapshot(...) abort |
1548 let home = get(s:, 'plug_home_org', g:plug_home) | 1965 let home = get(s:, 'plug_home_org', g:plug_home) |
1549 let [type, var, header] = s:is_win ? | 1966 let [type, var, header] = s:is_win ? |
1550 \ ['dosbatch', '%PLUG_HOME%', | 1967 \ ['dosbatch', '%PLUG_HOME%', |
1551 \ ['@echo off', ':: Generated by vim-plug', ':: '.strftime("%c"), '', | 1968 \ ['@echo off', ':: Generated by vim-plug', ':: '.strftime("%c"), '', |
1552 \ ':: Make sure to PlugUpdate first', '', 'set PLUG_HOME='.s:esc(home)]] : | 1969 \ ':: Make sure to PlugUpdate first', '', 'set PLUG_HOME='.home]] : |
1553 \ ['sh', '$PLUG_HOME', | 1970 \ ['sh', '$PLUG_HOME', |
1554 \ ['#!/bin/sh', '# Generated by vim-plug', '# '.strftime("%c"), '', | 1971 \ ['#!/bin/sh', '# Generated by vim-plug', '# '.strftime("%c"), '', |
1555 \ 'vim +PlugUpdate +qa', '', 'PLUG_HOME='.s:esc(home)]] | 1972 \ 'vim +PlugUpdate +qa', '', 'PLUG_HOME='.s:esc(home)]] |
1556 | 1973 |
1557 call s:prepare() | 1974 call s:prepare() |
1566 let anchor = line('$') - 1 | 1983 let anchor = line('$') - 1 |
1567 for dir in reverse(dirs) | 1984 for dir in reverse(dirs) |
1568 let sha = s:system_chomp('git rev-parse --short HEAD', dir) | 1985 let sha = s:system_chomp('git rev-parse --short HEAD', dir) |
1569 if !empty(sha) | 1986 if !empty(sha) |
1570 call append(anchor, printf('cd %s && git reset --hard %s', | 1987 call append(anchor, printf('cd %s && git reset --hard %s', |
1571 \ substitute(dir, '^'.g:plug_home, var, ''), sha)) | 1988 \ substitute(dir, '^\V'.escape(g:plug_home, '\'), var, ''), sha)) |
1572 redraw | 1989 redraw |
1573 endif | 1990 endif |
1574 endfor | 1991 endfor |
1575 | 1992 |
1576 if a:0 > 0 | 1993 if a:0 > 0 |