From 53cb1215f61e510ae6c82361a79da223d2376ba8 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Thu, 3 Apr 2014 08:25:29 +0200 Subject: [PATCH 1/2] Treat changed remotes as new plugins If one had this plugin: Plugin 'foo/bar' And now switches to another one with the same name: Plugin 'baz/bar' Recognise this scenario and replace the old plugin with the new one, rather than silently assuming they are the same. Fixes #367 #48 #183 #400 --- autoload/vundle/installer.vim | 110 +++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 16 deletions(-) diff --git a/autoload/vundle/installer.vim b/autoload/vundle/installer.vim index 4e3d36cb..3f1805da 100644 --- a/autoload/vundle/installer.vim +++ b/autoload/vundle/installer.vim @@ -3,7 +3,7 @@ " to g:bundle_dir. If a:bang is 1 it will also update all plugins (git pull). " " bang -- 1 or 0 -" ... -- any number of bundle specifications (seperate arguments) +" ... -- any number of bundle specifications (separate arguments) " --------------------------------------------------------------------------- func! vundle#installer#new(bang, ...) abort let bundles = (a:1 == '') ? @@ -323,27 +323,67 @@ endf " --------------------------------------------------------------------------- -" Install or update a given bundle object with git. +" Get the URL for the remote called 'origin' on the repository that +" corresponds to a given bundle. +" +" bundle -- a bundle object to check the repository for +" return -- the URL for the origin remote (string) +" --------------------------------------------------------------------------- +func! s:get_current_origin_url(bundle) abort + let cmd = 'cd '.vundle#installer#shellesc(a:bundle.path()).' && git config --get remote.origin.url' + let cmd = g:shellesc_cd(cmd) + let out = s:strip(s:system(cmd)) + return out +endf + + +" --------------------------------------------------------------------------- +" Create the appropriate sync command to run according to the current state of +" the local repository (clone, pull, reset, etc). +" +" In the case of a pull (update), also return the current sha, so that we can +" later check that there has been an upgrade. " " bang -- 0 if only new plugins should be installed, 1 if existing plugins " should be updated -" bundle -- a bundle object (dict) -" return -- 'todate' if nothing was updated or the repository was up to date, -" 'new' when the plugin was newly installed, 'updated' if some -" changes where pulled via git, 'error' if an error occurred in the -" shell command +" bundle -- a bundle object to create the sync command for +" return -- A list containing the command to run and the sha for the current +" HEAD " --------------------------------------------------------------------------- -func! s:sync(bang, bundle) abort - " Do not sync if this bundle is pinned - if a:bundle.is_pinned() - return 'pinned' - endif - +func! s:make_sync_command(bang, bundle) abort let git_dir = expand(a:bundle.path().'/.git/', 1) if isdirectory(git_dir) || filereadable(expand(a:bundle.path().'/.git', 1)) - if !(a:bang) | return 'todate' | endif - let cmd = 'cd '.vundle#installer#shellesc(a:bundle.path()).' && git pull && git submodule update --init --recursive' + let current_origin_url = s:get_current_origin_url(a:bundle) + if current_origin_url != a:bundle.uri + call s:log('Plugin URI change detected for Plugin ' . a:bundle.name) + call s:log('> Plugin ' . a:bundle.name . ' old URI: ' . current_origin_url) + call s:log('> Plugin ' . a:bundle.name . ' new URI: ' . a:bundle.uri) + " Directory names match but the origin remotes are not the same + let cmd_parts = [ + \ 'cd '.vundle#installer#shellesc(a:bundle.path()) , + \ 'git remote set-url origin ' . vundle#installer#shellesc(a:bundle.uri), + \ 'git fetch', + \ 'git reset --hard origin/HEAD', + \ 'git submodule update --init --recursive', + \ ] + let cmd = join(cmd_parts, ' && ') + let cmd = g:shellesc_cd(cmd) + let initial_sha = '' + return [cmd, initial_sha] + endif + + if !(a:bang) + " The repo exists, and no !, so leave as it is. + return ['', ''] + endif + + let cmd_parts = [ + \ 'cd '.vundle#installer#shellesc(a:bundle.path()), + \ 'git pull', + \ 'git submodule update --init --recursive', + \ ] + let cmd = join(cmd_parts, ' && ') let cmd = g:shellesc_cd(cmd) let get_current_sha = 'cd '.vundle#installer#shellesc(a:bundle.path()).' && git rev-parse HEAD' @@ -353,6 +393,33 @@ func! s:sync(bang, bundle) abort let cmd = 'git clone --recursive '.vundle#installer#shellesc(a:bundle.uri).' '.vundle#installer#shellesc(a:bundle.path()) let initial_sha = '' endif + return [cmd, initial_sha] +endf + + +" --------------------------------------------------------------------------- +" Install or update a given bundle object with git. +" +" bang -- 0 if only new plugins should be installed, 1 if existing plugins +" should be updated +" bundle -- a bundle object (dictionary) +" return -- a string indicating the status of the bundle installation: +" - todate : Nothing was updated or the repository was up to date +" - new : The plugin was newly installed +" - updated : Some changes where pulled via git +" - error : An error occurred in the shell command +" - pinned : The bundle is marked as pinned +" --------------------------------------------------------------------------- +func! s:sync(bang, bundle) abort + " Do not sync if this bundle is pinned + if a:bundle.is_pinned() + return 'pinned' + endif + + let [ cmd, initial_sha ] = s:make_sync_command(a:bang, a:bundle) + if empty(cmd) + return 'todate' + endif let out = s:system(cmd) call s:log('') @@ -427,7 +494,7 @@ endf " Add a log message to Vundle's internal logging variable. " " str -- the log message (string) -" prefix -- optional prefix for multiline entries (string) +" prefix -- optional prefix for multi-line entries (string) " return -- a:str " --------------------------------------------------------------------------- func! s:log(str, ...) abort @@ -441,4 +508,15 @@ func! s:log(str, ...) abort return a:str endf + +" --------------------------------------------------------------------------- +" Remove leading and trailing whitespace from a string +" +" str -- The string to rid of trailing and leading spaces +" return -- A string stripped of side spaces +" --------------------------------------------------------------------------- +func! s:strip(str) + return substitute(a:str, '\%^\_s*\(.\{-}\)\_s*\%$', '\1', '') +endf + " vim: set expandtab sts=2 ts=2 sw=2 tw=78 norl: From 3c6dd6d16be1cfb7a4d1244f693e977ab75c6f6d Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Tue, 15 Apr 2014 09:22:15 +0200 Subject: [PATCH 2/2] Check name collissions --- autoload/vundle/config.vim | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/autoload/vundle/config.vim b/autoload/vundle/config.vim index 1f942e1e..561f468f 100644 --- a/autoload/vundle/config.vim +++ b/autoload/vundle/config.vim @@ -7,6 +7,9 @@ " --------------------------------------------------------------------------- func! vundle#config#bundle(arg, ...) let bundle = vundle#config#init_bundle(a:arg, a:000) + if !s:check_bundle_name(bundle) + return + endif if exists('g:vundle_lazy_load') && g:vundle_lazy_load call add(g:bundles, bundle) else @@ -40,6 +43,7 @@ func! vundle#config#init() if !exists('g:bundles') | let g:bundles = [] | endif call s:rtp_rm_a() let g:bundles = [] + let g:bundle_names = {} endf @@ -79,6 +83,26 @@ func! vundle#config#init_bundle(name, opts) endf +" --------------------------------------------------------------------------- +" Check if the current bundle name has already been used in this running +" instance and show an error to that effect. +" +" bundle -- a bundle object whose name is to be checked +" return -- 0 if the bundle's name has been seen before, 1 otherwise +" --------------------------------------------------------------------------- +funct! s:check_bundle_name(bundle) + if has_key(g:bundle_names, a:bundle.name) + echoerr 'Vundle error: Name collision for Plugin ' . a:bundle.name_spec . + \ '. Plugin ' . g:bundle_names[a:bundle.name] . + \ ' previously used the name "' . a:bundle.name . '"' . + \ '. Skipping Plugin ' . a:bundle.name_spec . '.' + return 0 + endif + let g:bundle_names[a:bundle.name] = a:bundle.name_spec + return 1 +endf + + " --------------------------------------------------------------------------- " Parse the options which can be supplied with the bundle specification. " Corresponding documentation: vundle-plugins-configure