Mercurial > hg-stable
changeset 10549:b97736016273 stable
Merge with hg-i18n
author | Martin Geisler <mg@lazybytes.net> |
---|---|
date | Thu, 25 Feb 2010 17:06:32 +0100 |
parents | bae9bb09166b (diff) 167030b1757b (current diff) |
children | 8036bc1871c2 |
files | |
diffstat | 14 files changed, 1218 insertions(+), 283 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/shrink-revlog.py Wed Feb 24 19:47:51 2010 +0100 +++ b/contrib/shrink-revlog.py Thu Feb 25 17:06:32 2010 +0100 @@ -19,7 +19,7 @@ # e.g. by comparing "before" and "after" states of random changesets # (maybe: export before, shrink, export after, diff). -import os, tempfile +import os, tempfile, errno from mercurial import revlog, transaction, node, util from mercurial import changegroup from mercurial.i18n import _ @@ -91,9 +91,19 @@ finally: ui.progress(_('writing'), None, len(order)) -def report(ui, olddatafn, newdatafn): - oldsize = float(os.stat(olddatafn).st_size) - newsize = float(os.stat(newdatafn).st_size) +def report(ui, r1, r2): + def getsize(r): + s = 0 + for fn in (r.indexfile, r.datafile): + try: + s += os.stat(fn).st_size + except OSError, inst: + if inst.errno != errno.ENOENT: + raise + return s + + oldsize = float(getsize(r1)) + newsize = float(getsize(r2)) # argh: have to pass an int to %d, because a float >= 2^32 # blows up under Python 2.5 or earlier @@ -129,17 +139,23 @@ raise util.Abort(_('--revlog option must specify a revlog in %s, ' 'not %s') % (store, indexfn)) - datafn = indexfn[:-2] + '.d' if not os.path.exists(indexfn): raise util.Abort(_('no such file: %s') % indexfn) if '00changelog' in indexfn: raise util.Abort(_('shrinking the changelog ' 'will corrupt your repository')) - if not os.path.exists(datafn): - # This is just a lazy shortcut because I can't be bothered to - # handle all the special cases that entail from no .d file. - raise util.Abort(_('%s does not exist: revlog not big enough ' - 'to be worth shrinking') % datafn) + + ui.write(_('shrinking %s\n') % indexfn) + prefix = os.path.basename(indexfn)[:-1] + (tmpfd, tmpindexfn) = tempfile.mkstemp(dir=os.path.dirname(indexfn), + prefix=prefix, + suffix='.i') + os.close(tmpfd) + + r1 = revlog.revlog(util.opener(os.getcwd(), audit=False), indexfn) + r2 = revlog.revlog(util.opener(os.getcwd(), audit=False), tmpindexfn) + + datafn, tmpdatafn = r1.datafile, r2.datafile oldindexfn = indexfn + '.old' olddatafn = datafn + '.old' @@ -150,17 +166,6 @@ 'exists from a previous run; please clean up ' 'before running again') % (oldindexfn, olddatafn)) - ui.write(_('shrinking %s\n') % indexfn) - prefix = os.path.basename(indexfn)[:-1] - (tmpfd, tmpindexfn) = tempfile.mkstemp(dir=os.path.dirname(indexfn), - prefix=prefix, - suffix='.i') - tmpdatafn = tmpindexfn[:-2] + '.d' - os.close(tmpfd) - - r1 = revlog.revlog(util.opener(os.getcwd(), audit=False), indexfn) - r2 = revlog.revlog(util.opener(os.getcwd(), audit=False), tmpindexfn) - # Don't use repo.transaction(), because then things get hairy with # paths: some need to be relative to .hg, and some need to be # absolute. Doing it this way keeps things simple: everything is an @@ -170,30 +175,44 @@ open, repo.sjoin('journal')) + def ignoremissing(func): + def f(*args, **kw): + try: + return func(*args, **kw) + except OSError, inst: + if inst.errno != errno.ENOENT: + raise + return f + try: try: order = toposort(ui, r1) writerevs(ui, r1, r2, order, tr) - report(ui, datafn, tmpdatafn) + report(ui, r1, r2) tr.close() except: # Abort transaction first, so we truncate the files before # deleting them. tr.abort() - if os.path.exists(tmpindexfn): - os.unlink(tmpindexfn) - if os.path.exists(tmpdatafn): - os.unlink(tmpdatafn) + for fn in (tmpindexfn, tmpdatafn): + ignoremissing(os.unlink)(fn) raise if not opts.get('dry_run'): - # Racy since both files cannot be renamed atomically + # racy, both files cannot be renamed atomically + # copy files util.os_link(indexfn, oldindexfn) - util.os_link(datafn, olddatafn) + ignoremissing(util.os_link)(datafn, olddatafn) + # rename util.rename(tmpindexfn, indexfn) - util.rename(tmpdatafn, datafn) + try: + util.rename(tmpdatafn, datafn) + except OSError, inst: + if inst.errno != errno.ENOENT: + raise + ignoremissing(os.unlink)(datafn) else: - os.unlink(tmpindexfn) - os.unlink(tmpdatafn) + for fn in (tmpindexfn, tmpdatafn): + ignoremissing(os.unlink)(fn) finally: lock.release()
--- a/contrib/vim/patchreview.txt Wed Feb 24 19:47:51 2010 +0100 +++ b/contrib/vim/patchreview.txt Thu Feb 25 17:06:32 2010 +0100 @@ -1,30 +1,38 @@ -*patchreview.txt* Vim global plugin for doing single or multipatch code reviews +*patchreview.txt* Vim global plugin for doing single, multi-patch or diff code reviews + Version v0.2.1 (for Vim version 7.0 or higher) - Author: Manpreet Singh (junkblocker-CAT-yahoo-DOG-com) - (Replace -CAT- and -DOG- with @ and . first) - Copyright (C) 2006 by Manpreet Singh + Author: Manpreet Singh < junkblocker@yahoo.com > + Copyright (C) 2006-2010 by Manpreet Singh License : This file is placed in the public domain. ============================================================================= -CONTENTS *patchreview* *patchreview-contents* +CONTENTS *patchreview* *diffreview* *patchreview-contents* 1. Contents.........................................: |patchreview-contents| 2. Introduction.....................................: |patchreview-intro| 3. PatchReview options..............................: |patchreview-options| 4. PatchReview Usage................................: |patchreview-usage| - 4.1 PatchReview Usage............................: |:PatchReview| - 4.2 PatchReview Usage............................: |:PatchReviewCleanup| + 4.1 DiffReview Usage.............................: |:DiffReview| + 4.2 PatchReview Usage............................: |:PatchReview| + 4.3 DiffReviewCleanup Usage......................: |:DiffReviewCleanup| + 4.4 PatchReviewCleanup Usage.....................: |:PatchReviewCleanup| ============================================================================= PatchReview Introduction *patchreview-intro* -The Patch Review plugin allows single or multipatch code review to be done in -VIM. VIM provides the |:diffpatch| command to do single file reviews but can -not handle patch files containing multiple patches as is common with software -development projects. This plugin provides that missing functionality. It also -tries to improve on |:diffpatch|'s behaviour of creating the patched files in +The Patch Review plugin allows easy single or multipatch code or diff reviews. + +It opens each affected file in the patch or in a workspace diff in a diff view +in a separate tab. + +VIM provides the |:diffpatch| and related commands to do single file reviews +but can not handle patch files containing multiple patches as is common with +software development projects. This plugin provides that missing +functionality. + +It also improves on |:diffpatch|'s behaviour of creating the patched files in the same directory as original file which can lead to project workspace pollution. @@ -32,66 +40,81 @@ PatchReview Options *patchreview-options* - g:patchreview_filterdiff : Optional path to filterdiff binary. PatchReview - tries to locate filterdiff on system path - automatically. If the binary is not on system - path, this option tell PatchReview the full path - to the binary. This option, if specified, - overrides the default filterdiff binary on the - path. + g:patchreview_tmpdir = {string} + Optional path where the plugin can save temporary files. If this is not + specified, the plugin tries to use TMP, TEMP and TMPDIR environment + variables in succession. + + examples: + (On Windows) > + let g:patchreview_tmpdir = 'c:\\tmp' +< + (On *nix systems) > + let g:patchreview_tmpdir = '~/tmp' +< + + g:patchreview_filterdiff = {string} + Optional path to filterdiff binary. PatchReview tries to locate + filterdiff on system path automatically. If the binary is not on system + path, this option tell PatchReview the full path to the binary. This + option, if specified, overrides the default filterdiff binary on the + path. examples: (On Windows with Cygwin) - +> let g:patchreview_filterdiff = 'c:\\cygwin\\bin\\filterdiff.exe' - +< (On *nix systems) - +> let g:patchreview_filterdiff = '/usr/bin/filterdiff' - - g:patchreview_patch : Optional path to patch binary. PatchReview tries - to locate patch on system path automatically. If - the binary is not on system path, this option - tell PatchReview the full path to the binary. - This option, if specified, overrides the default - patch binary on the path. - - examples: - (On Windows with Cygwin) - - let g:patchreview_patch = 'c:\\cygwin\\bin\\patch.exe' - - (On *nix systems) - - let g:patchreview_patch = '/usr/bin/gpatch' - - - g:patchreview_tmpdir : Optional path where the plugin can save temporary - files. If this is not specified, the plugin tries to - use TMP, TEMP and TMPDIR environment variables in - succession. +< + g:patchreview_patch = {string} + Optional path to patch binary. PatchReview tries to locate patch on + system path automatically. If the binary is not on system path, this + option tell PatchReview the full path to the binary. This option, if + specified, overrides the default patch binary on the path. examples: - (On Windows) let g:patchreview_tmpdir = 'c:\\tmp' - (On *nix systems) let g:patchreview_tmpdir = '~/tmp' + (On Windows with Cygwin) > + let g:patchreview_patch = 'c:\\cygwin\\bin\\patch.exe' +< + (On *nix systems) > + let g:patchreview_patch = '/usr/bin/gpatch' +< ============================================================================= PatchReview Usage *patchreview-usage* + *:DiffReview* + + :DiffReview + + Perform a diff review in the current directory under version control. + Currently supports Mercurial (hg), Subversion (svn), CVS, Bazaar (bzr) and + Monotone. + *:PatchReview* :PatchReview patchfile_path [optional_source_directory] Perform a patch review in the current directory based on the supplied patchfile_path. If optional_source_directory is specified, patchreview is - done on that directory. Othewise, the current directory is assumed to be + done on that directory. Otherwise, the current directory is assumed to be the source directory. + + Only supports context or unified format patches. + + *:DiffReviewCleanup* *:PatchReviewCleanup* + :DiffReviewCleanup :PatchReviewCleanup - After you are done using the :PatchReview command, you can cleanup the - temporary files in the temporary directory using this command. + After you are done using the :DiffReview or :PatchReview command, you can + cleanup the temporary files in the temporary directory using either of + these commands. -============================================================================= -vim: ft=help:ts=2:sts=2:sw=2:tw=78:tw=78 +------------------------------------------------------------------------------ + + vim: ft=help:ts=2:sts=2:sw=2:tw=78:norl:
--- a/contrib/vim/patchreview.vim Wed Feb 24 19:47:51 2010 +0100 +++ b/contrib/vim/patchreview.vim Thu Feb 25 17:06:32 2010 +0100 @@ -1,113 +1,148 @@ -" Vim global plugin for doing single or multipatch code reviews"{{{ +" VIM plugin for doing single, multi-patch or diff code reviews {{{ +" Home: http://www.vim.org/scripts/script.php?script_id=1563 -" Version : 0.1 "{{{ -" Last Modified : Thu 25 May 2006 10:15:11 PM PDT -" Author : Manpreet Singh (junkblocker AT yahoo DOT com) -" Copyright : 2006 by Manpreet Singh +" Version : 0.2.1 "{{{ +" Author : Manpreet Singh < junkblocker@yahoo.com > +" Copyright : 2006-2010 by Manpreet Singh " License : This file is placed in the public domain. +" No warranties express or implied. Use at your own risk. " -" History : 0.1 - First released +" Changelog : +" +" 0.2.1 - Minor temp directory autodetection logic and cleanup +" +" 0.2 - Removed the need for filterdiff by implemeting it in pure vim script +" - Added DiffReview command for reverse (changed repository to +" pristine state) reviews. +" (PatchReview does pristine repository to patch review) +" - DiffReview does automatic detection and generation of diffs for +" various Source Control systems +" - Skip load if VIM 7.0 or higher unavailable +" +" 0.1 - First released "}}} + " Documentation: "{{{ " =========================================================================== -" This plugin allows single or multipatch code reviews to be done in VIM. Vim -" has :diffpatch command to do single file reviews but can not handle patch -" files containing multiple patches. This plugin provides that missing -" functionality and doesn't require the original file to be open. +" This plugin allows single or multiple, patch or diff based code reviews to +" be easily done in VIM. VIM has :diffpatch command to do single file reviews +" but a) can not handle patch files containing multiple patches or b) do +" automated diff generation for various version control systems. This plugin +" attempts to provide those functionalities. It opens each changed / added or +" removed file diff in new tabs. +" +" Installing: " -" Installing: "{{{ +" For a quick start... +" +" Requirements: +" +" 1) VIM 7.0 or higher built with +diff option. " -" For a quick start... +" 2) A gnu compatible patch command installed. This is the standard patch +" command on Linux, Mac OS X, *BSD, Cygwin or /usr/bin/gpatch on newer +" Solaris. " -" Requirements: "{{{ +" 3) Optional (but recommended for speed) " -" 1) (g)vim 7.0 or higher built with +diff option. -" 2) patch and patchutils ( http://cyberelk.net/tim/patchutils/ ) installed -" for your OS. For windows it is availble from Cygwin ( -" http://www.cygwin.com ) or GnuWin32 ( http://gnuwin32.sourceforge.net/ -" ). -""}}} -" Install: "{{{ +" Install patchutils ( http://cyberelk.net/tim/patchutils/ ) for your +" OS. For windows it is availble from Cygwin +" +" http://www.cygwin.com +" +" or GnuWin32 +" +" http://gnuwin32.sourceforge.net/ +" +" Install: " -" 1) Extract this in your $VIM/vimfiles or $HOME/.vim directory and restart -" vim. +" 1) Extract the zip in your $HOME/.vim or $VIM/vimfiles directory and +" restart vim. The directory location relevant to your platform can be +" seen by running :help add-global-plugin in vim. " -" 2) Make sure that you have filterdiff from patchutils and patch commands -" installed. +" 2) Restart vim. " -" 3) Optinally, specify the locations to filterdiff and patch commands and -" location of a temporary directory to use in your .vimrc. +" Configuration: " -" let g:patchreview_filterdiff = '/path/to/filterdiff' -" let g:patchreview_patch = '/path/to/patch' +" Optionally, specify the locations to these filterdiff and patch commands +" and location of a temporary directory to use in your .vimrc. +" +" let g:patchreview_patch = '/path/to/gnu/patch' " let g:patchreview_tmpdir = '/tmp/or/something' " -" 4) Optionally, generate help tags to use help +" " If you are using filterdiff +" let g:patchreview_filterdiff = '/path/to/filterdiff' " -" :helptags ~/.vim/doc -" or -" :helptags c:\vim\vimfiles\doc -""}}} -""}}} -" Usage: "{{{ " -" :PatchReview path_to_submitted_patchfile [optional_source_directory] " -" after review is done +" Usage: " -" :PatchReviewCleanup +" Please see :help patchreview or :help diffreview for details. " -" See :help patchreview for details after you've created help tags. ""}}} -"}}} -" Code "{{{ -" Enabled only during development "{{{ +" Enabled only during development " unlet! g:loaded_patchreview " DEBUG " unlet! g:patchreview_tmpdir " DEBUG +" unlet! g:patchreview_patch " DEBUG " unlet! g:patchreview_filterdiff " DEBUG -" unlet! g:patchreview_patch " DEBUG -"}}} +" let g:patchreview_patch = 'patch' " DEBUG -" load only once "{{{ -if exists('g:loaded_patchreview') +if v:version < 700 + finish +endif +if ! has('diff') + call confirm('patchreview.vim plugin needs (G)VIM built with +diff support to work.') + finish +endif + +" load only once +if (! exists('g:patchreview_debug') && exists('g:loaded_patchreview')) || &compatible finish endif -let g:loaded_patchreview=1 -let s:msgbufname = 'Patch Review Messages' +let g:loaded_patchreview="0.2.1" + +let s:msgbufname = '-PatchReviewMessages-' + +function! <SID>Debug(str) "{{{ + if exists('g:patchreview_debug') + Pecho 'DEBUG: ' . a:str + endif +endfunction +command! -nargs=+ -complete=expression Debug call s:Debug(<args>) "}}} -function! <SID>PR_wipeMsgBuf() "{{{ - let s:winnum = bufwinnr(s:msgbufname) - if s:winnum != -1 " If the window is already open, jump to it - let s:cur_winnr = winnr() - if winnr() != s:winnum - exe s:winnum . 'wincmd w' +function! <SID>PR_wipeMsgBuf() "{{{ + let winnum = bufwinnr(s:msgbufname) + if winnum != -1 " If the window is already open, jump to it + let cur_winnr = winnr() + if winnr() != winnum + exe winnum . 'wincmd w' exe 'bw' - exe s:cur_winnr . 'wincmd w' + exe cur_winnr . 'wincmd w' endif endif endfunction "}}} -function! <SID>PR_echo(...) "{{{ - " Usage: PR_echo(msg, [return_to_original_window_flag]) +function! <SID>Pecho(...) "{{{ + " Usage: Pecho(msg, [return_to_original_window_flag]) " default return_to_original_window_flag = 0 " - let s:cur_winnr = winnr() - let s:winnum = bufwinnr(s:msgbufname) - if s:winnum != -1 " If the window is already open, jump to it - if winnr() != s:winnum - exe s:winnum . 'wincmd w' + let cur_winnr = winnr() + let winnum = bufwinnr(s:msgbufname) + if winnum != -1 " If the window is already open, jump to it + if winnr() != winnum + exe winnum . 'wincmd w' endif else - let s:bufnum = bufnr(s:msgbufname) - if s:bufnum == -1 - let s:wcmd = s:msgbufname + let bufnum = bufnr(s:msgbufname) + if bufnum == -1 + let wcmd = s:msgbufname else - let s:wcmd = '+buffer' . s:bufnum + let wcmd = '+buffer' . bufnum endif - exe 'silent! botright 5split ' . s:wcmd + exe 'silent! botright 5split ' . wcmd endif setlocal modifiable setlocal buftype=nofile @@ -121,23 +156,26 @@ exe ':$' setlocal nomodifiable if a:0 > 1 && a:2 - exe s:cur_winnr . 'wincmd w' + exe cur_winnr . 'wincmd w' endif endfunction + +command! -nargs=+ -complete=expression Pecho call s:Pecho(<args>) "}}} -function! <SID>PR_checkBinary(BinaryName) "{{{ +function! <SID>PR_checkBinary(BinaryName) "{{{ " Verify that BinaryName is specified or available if ! exists('g:patchreview_' . a:BinaryName) if executable(a:BinaryName) let g:patchreview_{a:BinaryName} = a:BinaryName return 1 else - call s:PR_echo('g:patchreview_' . a:BinaryName . ' is not defined and could not be found on path. Please define it in your .vimrc.') + Pecho 'g:patchreview_' . a:BinaryName . ' is not defined and ' . a:BinaryName . ' command could not be found on path.' + Pecho 'Please define it in your .vimrc.' return 0 endif elseif ! executable(g:patchreview_{a:BinaryName}) - call s:PR_echo('Specified g:patchreview_' . a:BinaryName . ' [' . g:patchreview_{a.BinaryName} . '] is not executable.') + Pecho 'Specified g:patchreview_' . a:BinaryName . ' [' . g:patchreview_{a:BinaryName} . '] is not executable.' return 0 else return 1 @@ -145,11 +183,11 @@ endfunction "}}} -function! <SID>PR_GetTempDirLocation(Quiet) "{{{ +function! <SID>PR_GetTempDirLocation(Quiet) "{{{ if exists('g:patchreview_tmpdir') if ! isdirectory(g:patchreview_tmpdir) || ! filewritable(g:patchreview_tmpdir) if ! a:Quiet - call s:PR_echo('Temporary directory specified by g:patchreview_tmpdir [' . g:patchreview_tmpdir . '] is not accessible.') + Pecho 'Temporary directory specified by g:patchreview_tmpdir [' . g:patchreview_tmpdir . '] is not accessible.' return 0 endif endif @@ -160,14 +198,34 @@ elseif exists("$TMPDIR") && isdirectory($TMPDIR) && filewritable($TMPDIR) let g:patchreview_tmpdir = $TMPDIR else - if ! a:Quiet - call s:PR_echo('Could not figure out a temporary directory to use. Please specify g:patchreview_tmpdir in your .vimrc.') + if has("unix") + if isdirectory("/tmp") + let g:patchreview_tmpdir = "/tmp" + elseif isdirectory(expand("~/tmp")) + let g:patchreview_tmpdir = expand("~/tmp") + endif + elseif has("win32") + if isdirectory('c:\\tmp') + let g:patchreview_tmpdir = 'c:\\tmp' + elseif isdirectory('c:\\temp') + let g:patchreview_tmpdir = 'c:\\temp' + elseif isdirectory('c:\\windows\\temp') + let g:patchreview_tmpdir = 'c:\\windows\\temp' + elseif isdirectory($USERPROFILE . '\Local Settings\Temp') # NOTE : No \ issue here + let g:patchreview_tmpdir = $USERPROFILE . '\Local Settings\Temp' + endif + endif + if !exists('g:patchreview_tmpdir') + if ! a:Quiet + Pecho 'Could not figure out a temporary directory to use. Please specify g:patchreview_tmpdir in your .vimrc.' + endif return 0 endif endif + let g:patchreview_tmpdir = expand(g:patchreview_tmpdir, ':p') let g:patchreview_tmpdir = g:patchreview_tmpdir . '/' let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '\\', '/', 'g') - let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/+$', '/', '') + let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/\+$', '/', '') if has('win32') let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/', '\\', 'g') endif @@ -175,158 +233,694 @@ endfunction "}}} -function! <SID>PatchReview(...) "{{{ - " VIM 7+ required"{{{ - if version < 700 - call s:PR_echo('This plugin needs VIM 7 or higher') +function! <SID>ExtractDiffsNative(...) "{{{ + " Sets g:patches = {'reason':'', 'patch':[ + " { + " 'filename': filepath + " 'type' : '+' | '-' | '!' + " 'content' : patch text for this file + " }, + " ... + " ]} + let g:patches = {'reason' : '', 'patch' : []} + " TODO : User pointers into lines list rather then use collect + if a:0 == 0 + let g:patches['reason'] = "ExtractDiffsNative expects at least a patchfile argument" + return + endif + let patchfile = expand(a:1, ':p') + if a:0 > 1 + let patch = a:2 + endif + if ! filereadable(patchfile) + let g:patches['reason'] = "File " . patchfile . " is not readable" return endif + unlet! filterdiffcmd + let filterdiffcmd = '' . g:patchreview_filterdiff . ' --list -s ' . patchfile + let fileslist = split(system(filterdiffcmd), '[\r\n]') + for filewithchangetype in fileslist + if filewithchangetype !~ '^[!+-] ' + Pecho '*** Skipping review generation due to unknown change for [' . filewithchangetype . ']' + continue + endif + + unlet! this_patch + let this_patch = {} + + unlet! relpath + let relpath = substitute(filewithchangetype, '^. ', '', '') + + let this_patch['filename'] = relpath + + if filewithchangetype =~ '^! ' + let this_patch['type'] = '!' + elseif filewithchangetype =~ '^+ ' + let this_patch['type'] = '+' + elseif filewithchangetype =~ '^- ' + let this_patch['type'] = '-' + endif + + unlet! filterdiffcmd + let filterdiffcmd = '' . g:patchreview_filterdiff . ' -i ' . relpath . ' ' . patchfile + let this_patch['content'] = split(system(filterdiffcmd), '[\n\r]') + let g:patches['patch'] += [this_patch] + Debug "Patch collected for " . relpath + endfor +endfunction "}}} - let s:save_shortmess = &shortmess - set shortmess+=aW - call s:PR_wipeMsgBuf() - - " Check passed arguments "{{{ +function! <SID>ExtractDiffsPureVim(...) "{{{ + " Sets g:patches = {'reason':'', 'patch':[ + " { + " 'filename': filepath + " 'type' : '+' | '-' | '!' + " 'content' : patch text for this file + " }, + " ... + " ]} + let g:patches = {'reason' : '', 'patch' : []} + " TODO : User pointers into lines list rather then use collect if a:0 == 0 - call s:PR_echo('PatchReview command needs at least one argument specifying a patchfile path.') - let &shortmess = s:save_shortmess + let g:patches['reason'] = "ExtractDiffsPureVim expects at least a patchfile argument" + return + endif + let patchfile = expand(a:1, ':p') + if a:0 > 1 + let patch = a:2 + endif + if ! filereadable(patchfile) + let g:patches['reason'] = "File " . patchfile . " is not readable" return endif - if a:0 >= 1 && a:0 <= 2 - let s:PatchFilePath = expand(a:1, ':p') - if ! filereadable(s:PatchFilePath) - call s:PR_echo('File [' . s:PatchFilePath . '] is not accessible.') - let &shortmess = s:save_shortmess + call s:PR_wipeMsgBuf() + let collect = [] + let linum = 0 + let lines = readfile(patchfile) + let linescount = len(lines) + State 'START' + while linum < linescount + let line = lines[linum] + let linum += 1 + if State() == 'START' + let mat = matchlist(line, '^--- \([^\t]\+\).*$') + if ! empty(mat) && mat[1] != '' + State 'MAYBE_UNIFIED_DIFF' + let p_first_file = mat[1] + let collect = [line] + Debug line . State() + continue + endif + let mat = matchlist(line, '^\*\*\* \([^\t]\+\).*$') + if ! empty(mat) && mat[1] != '' + State 'MAYBE_CONTEXT_DIFF' + let p_first_file = mat[1] + let collect = [line] + Debug line . State() + continue + endif + continue + elseif State() == 'MAYBE_CONTEXT_DIFF' + let mat = matchlist(line, '^--- \([^\t]\+\).*$') + if empty(mat) || mat[1] == '' + State 'START' + let linum -= 1 + continue + Debug 'Back to square one ' . line() + endif + let p_second_file = mat[1] + if p_first_file == '/dev/null' + if p_second_file == '/dev/null' + let g:patches['reason'] = "Malformed diff found at line " . linum + return + endif + let p_type = '+' + let filepath = p_second_file + else + if p_second_file == '/dev/null' + let p_type = '-' + let filepath = p_first_file + else + let p_type = '!' + let filepath = p_first_file + endif + endif + State 'EXPECT_15_STARS' + let collect += [line] + Debug line . State() + elseif State() == 'EXPECT_15_STARS' + if line !~ '^*\{15}$' + State 'START' + let linum -= 1 + Debug line . State() + continue + endif + State 'EXPECT_CONTEXT_CHUNK_HEADER_1' + let collect += [line] + Debug line . State() + elseif State() == 'EXPECT_CONTEXT_CHUNK_HEADER_1' + let mat = matchlist(line, '^\*\*\* \(\d\+,\)\?\(\d\+\) \*\*\*\*$') + if empty(mat) || mat[1] == '' + State 'START' + let linum -= 1 + Debug line . State() + continue + endif + let collect += [line] + State 'SKIP_CONTEXT_STUFF_1' + Debug line . State() + continue + elseif State() == 'SKIP_CONTEXT_STUFF_1' + if line !~ '^[ !+].*$' + let mat = matchlist(line, '^--- \(\d\+\),\(\d\+\) ----$') + if ! empty(mat) && mat[1] != '' && mat[2] != '' + let goal_count = mat[2] - mat[1] + 1 + let c_count = 0 + State 'READ_CONTEXT_CHUNK' + let collect += [line] + Debug line . State() . " Goal count set to " . goal_count + continue + endif + State 'START' + let linum -= 1 + Debug line . State() + continue + endif + let collect += [line] + continue + elseif State() == 'READ_CONTEXT_CHUNK' + let c_count += 1 + if c_count == goal_count + let collect += [line] + State 'BACKSLASH_OR_CRANGE_EOF' + continue + else " goal not met yet + let mat = matchlist(line, '^\([\\!+ ]\).*$') + if empty(mat) || mat[1] == '' + let linum -= 1 + State 'START' + Debug line . State() + continue + endif + let collect += [line] + continue + endif + elseif State() == 'BACKSLASH_OR_CRANGE_EOF' + if line =~ '^\\ No newline.*$' " XXX: Can we go to another chunk from here?? + let collect += [line] + let this_patch = {} + let this_patch['filename'] = filepath + let this_patch['type'] = p_type + let this_patch['content'] = collect + let g:patches['patch'] += [this_patch] + Debug "Patch collected for " . filepath + State 'START' + continue + endif + if line =~ '^\*\{15}$' + let collect += [line] + State 'EXPECT_CONTEXT_CHUNK_HEADER_1' + Debug line . State() + continue + endif + let this_patch = {} + let this_patch['filename'] = filepath + let this_patch['type'] = p_type + let this_patch['content'] = collect + let g:patches['patch'] += [this_patch] + let linum -= 1 + State 'START' + Debug "Patch collected for " . filepath + Debug line . State() + continue + elseif State() == 'MAYBE_UNIFIED_DIFF' + let mat = matchlist(line, '^+++ \([^\t]\+\).*$') + if empty(mat) || mat[1] == '' + State 'START' + let linum -= 1 + Debug line . State() + continue + endif + let p_second_file = mat[1] + if p_first_file == '/dev/null' + if p_second_file == '/dev/null' + let g:patches['reason'] = "Malformed diff found at line " . linum + return + endif + let p_type = '+' + let filepath = p_second_file + else + if p_second_file == '/dev/null' + let p_type = '-' + let filepath = p_first_file + else + let p_type = '!' + let filepath = p_first_file + endif + endif + State 'EXPECT_UNIFIED_RANGE_CHUNK' + let collect += [line] + Debug line . State() + continue + elseif State() == 'EXPECT_UNIFIED_RANGE_CHUNK' + let mat = matchlist(line, '^@@ -\(\d\+,\)\?\(\d\+\) +\(\d\+,\)\?\(\d\+\) @@$') + if ! empty(mat) + let old_goal_count = mat[2] + let new_goal_count = mat[4] + let o_count = 0 + let n_count = 0 + Debug "Goal count set to " . old_goal_count . ', ' . new_goal_count + State 'READ_UNIFIED_CHUNK' + let collect += [line] + Debug line . State() + continue + endif + State 'START' + Debug line . State() + continue + elseif State() == 'READ_UNIFIED_CHUNK' + if o_count == old_goal_count && n_count == new_goal_count + if line =~ '^\\.*$' " XXX: Can we go to another chunk from here?? + let collect += [line] + let this_patch = {} + let this_patch['filename'] = filepath + let this_patch['type'] = p_type + let this_patch['content'] = collect + let g:patches['patch'] += [this_patch] + Debug "Patch collected for " . filepath + State 'START' + continue + endif + let mat = matchlist(line, '^@@ -\(\d\+,\)\?\(\d\+\) +\(\d\+,\)\?\(\d\+\) @@$') + if ! empty(mat) + let old_goal_count = mat[2] + let new_goal_count = mat[4] + let o_count = 0 + let n_count = 0 + Debug "Goal count set to " . old_goal_count . ', ' . new_goal_count + let collect += [line] + Debug line . State() + continue + endif + let this_patch = {} + let this_patch['filename'] = filepath + let this_patch['type'] = p_type + let this_patch['content'] = collect + let g:patches['patch'] += [this_patch] + Debug "Patch collected for " . filepath + let linum -= 1 + State 'START' + Debug line . State() + continue + else " goal not met yet + let mat = matchlist(line, '^\([\\+ -]\).*$') + if empty(mat) || mat[1] == '' + let linum -= 1 + State 'START' + continue + endif + let chr = mat[1] + if chr == '+' + let n_count += 1 + endif + if chr == ' ' + let o_count += 1 + let n_count += 1 + endif + if chr == '-' + let o_count += 1 + endif + let collect += [line] + Debug line . State() + continue + endif + else + let g:patches['reason'] = "Internal error: Do not use the plugin anymore and if possible please send the diff or patch file you tried it with to Manpreet Singh <junkblocker@yahoo.com>" return endif - if a:0 == 2 - let s:SrcDirectory = expand(a:2, ':p') - if ! isdirectory(s:SrcDirectory) - call s:PR_echo('[' . s:SrcDirectory . '] is not a directory') - let &shortmess = s:save_shortmess - return - endif - try - exe 'cd ' . s:SrcDirectory - catch /^.*E344.*/ - call s:PR_echo('Could not change to directory [' . s:SrcDirectory . ']') - let &shortmess = s:save_shortmess - return - endtry + endwhile + "Pecho State() + if (State() == 'READ_CONTEXT_CHUNK' && c_count == goal_count) || (State() == 'READ_UNIFIED_CHUNK' && n_count == new_goal_count && o_count == old_goal_count) + let this_patch = {} + let this_patch['filename'] = filepath + let this_patch['type'] = p_type + let this_patch['content'] = collect + let g:patches['patch'] += [this_patch] + Debug "Patch collected for " . filepath + endif + return +endfunction +"}}} + +function! State(...) " For easy manipulation of diff extraction state "{{{ + if a:0 != 0 + let s:STATE = a:1 + else + if ! exists('s:STATE') + let s:STATE = 'START' endif - else - call s:PR_echo('PatchReview command needs at most two arguments: patchfile path and optional source directory path.') - let &shortmess = s:save_shortmess - return + return s:STATE endif +endfunction +com! -nargs=+ -complete=expression State call State(<args>) "}}} - " Verify that filterdiff and patch are specified or available "{{{ - if ! s:PR_checkBinary('filterdiff') || ! s:PR_checkBinary('patch') - let &shortmess = s:save_shortmess +function! <SID>PatchReview(...) "{{{ + let s:save_shortmess = &shortmess + let s:save_aw = &autowrite + let s:save_awa = &autowriteall + set shortmess=aW + call s:PR_wipeMsgBuf() + let s:reviewmode = 'patch' + call s:_GenericReview(a:000) + let &autowriteall = s:save_awa + let &autowrite = s:save_aw + let &shortmess = s:save_shortmess +endfunction +"}}} + +function! <SID>_GenericReview(argslist) "{{{ + " diff mode: + " arg1 = patchfile + " arg2 = strip count + " patch mode: + " arg1 = patchfile + " arg2 = strip count + " arg3 = directory + + " VIM 7+ required + if version < 700 + Pecho 'This plugin needs VIM 7 or higher' return endif - let s:retval = s:PR_GetTempDirLocation(0) - if ! s:retval - let &shortmess = s:save_shortmess + " +diff required + if ! has('diff') + Pecho 'This plugin needs VIM built with +diff feature.' + return + endif + + + if s:reviewmode == 'diff' + let patch_R_option = ' -t -R ' + elseif s:reviewmode == 'patch' + let patch_R_option = '' + else + Pecho 'Fatal internal error in patchreview.vim plugin' + return + endif + + " Check passed arguments + if len(a:argslist) == 0 + Pecho 'PatchReview command needs at least one argument specifying a patchfile path.' return endif -"}}} + let StripCount = 0 + if len(a:argslist) >= 1 && ((s:reviewmode == 'patch' && len(a:argslist) <= 3) || (s:reviewmode == 'diff' && len(a:argslist) == 2)) + let PatchFilePath = expand(a:argslist[0], ':p') + if ! filereadable(PatchFilePath) + Pecho 'File [' . PatchFilePath . '] is not accessible.' + return + endif + if len(a:argslist) >= 2 && s:reviewmode == 'patch' + let s:SrcDirectory = expand(a:argslist[1], ':p') + if ! isdirectory(s:SrcDirectory) + Pecho '[' . s:SrcDirectory . '] is not a directory' + return + endif + try + " Command line has already escaped the path + exe 'cd ' . s:SrcDirectory + catch /^.*E344.*/ + Pecho 'Could not change to directory [' . s:SrcDirectory . ']' + return + endtry + endif + if s:reviewmode == 'diff' + " passed in by default + let StripCount = eval(a:argslist[1]) + elseif s:reviewmode == 'patch' + let StripCount = 1 + " optional strip count + if len(a:argslist) == 3 + let StripCount = eval(a:argslist[2]) + endif + endif + else + if s:reviewmode == 'patch' + Pecho 'PatchReview command needs at most three arguments: patchfile path, optional source directory path and optional strip count.' + elseif s:reviewmode == 'diff' + Pecho 'DiffReview command accepts no arguments.' + endif + return + endif - " Requirements met, now execute "{{{ - let s:PatchFilePath = fnamemodify(s:PatchFilePath, ':p') - call s:PR_echo('Patch file : ' . s:PatchFilePath) - call s:PR_echo('Source directory: ' . getcwd()) - call s:PR_echo('------------------') - let s:theFilterDiffCommand = '' . g:patchreview_filterdiff . ' --list -s ' . s:PatchFilePath - let s:theFilesString = system(s:theFilterDiffCommand) - let s:theFilesList = split(s:theFilesString, '[\r\n]') - for s:filewithchangetype in s:theFilesList - if s:filewithchangetype !~ '^[!+-] ' - call s:PR_echo('*** Skipping review generation due to understood change for [' . s:filewithchangetype . ']', 1) + " Verify that patch command and temporary directory are available or specified + if ! s:PR_checkBinary('patch') + return + endif + + let retval = s:PR_GetTempDirLocation(0) + if ! retval + return + endif + + " Requirements met, now execute + let PatchFilePath = fnamemodify(PatchFilePath, ':p') + if s:reviewmode == 'patch' + Pecho 'Patch file : ' . PatchFilePath + endif + Pecho 'Source directory: ' . getcwd() + Pecho '------------------' + if s:PR_checkBinary('filterdiff') + Debug "Using filterdiff" + call s:ExtractDiffsNative(PatchFilePath) + else + Debug "Using own diff extraction (slower)" + call s:ExtractDiffsPureVim(PatchFilePath) + endif + for patch in g:patches['patch'] + if patch.type !~ '^[!+-]$' + Pecho '*** Skipping review generation due to unknown change [' . patch.type . ']', 1 continue endif - unlet! s:RelativeFilePath - let s:RelativeFilePath = substitute(s:filewithchangetype, '^. ', '', '') - let s:RelativeFilePath = substitute(s:RelativeFilePath, '^[a-z][^\\\/]*[\\\/]' , '' , '') - if s:filewithchangetype =~ '^! ' - let s:msgtype = 'Modification : ' - elseif s:filewithchangetype =~ '^+ ' - let s:msgtype = 'Addition : ' - elseif s:filewithchangetype =~ '^- ' - let s:msgtype = 'Deletion : ' + unlet! relpath + let relpath = patch.filename + " XXX: svn diff and hg diff produce different kind of outputs, one requires + " XXX: stripping but the other doesn't. We need to take care of that + let stripmore = StripCount + let StrippedRelativeFilePath = relpath + while stripmore > 0 + " strip one + let StrippedRelativeFilePath = substitute(StrippedRelativeFilePath, '^[^\\\/]\+[^\\\/]*[\\\/]' , '' , '') + let stripmore -= 1 + endwhile + if patch.type == '!' + if s:reviewmode == 'patch' + let msgtype = 'Patch modifies file: ' + elseif s:reviewmode == 'diff' + let msgtype = 'File has changes: ' + endif + elseif patch.type == '+' + if s:reviewmode == 'patch' + let msgtype = 'Patch adds file : ' + elseif s:reviewmode == 'diff' + let msgtype = 'New file : ' + endif + elseif patch.type == '-' + if s:reviewmode == 'patch' + let msgtype = 'Patch removes file : ' + elseif s:reviewmode == 'diff' + let msgtype = 'Removed file : ' + endif endif - let s:bufnum = bufnr(s:RelativeFilePath) - if buflisted(s:bufnum) && getbufvar(s:bufnum, '&mod') - call s:PR_echo('Old buffer for file [' . s:RelativeFilePath . '] exists in modified state. Skipping review.', 1) + let bufnum = bufnr(relpath) + if buflisted(bufnum) && getbufvar(bufnum, '&mod') + Pecho 'Old buffer for file [' . relpath . '] exists in modified state. Skipping review.', 1 continue endif - let s:tmpname = substitute(s:RelativeFilePath, '/', '_', 'g') - let s:tmpname = substitute(s:tmpname, '\\', '_', 'g') - let s:tmpname = g:patchreview_tmpdir . 'PatchReview.' . s:tmpname . '.' . strftime('%Y%m%d%H%M%S') + let tmpname = substitute(relpath, '/', '_', 'g') + let tmpname = substitute(tmpname, '\\', '_', 'g') + let tmpname = g:patchreview_tmpdir . 'PatchReview.' . tmpname . '.' . strftime('%Y%m%d%H%M%S') if has('win32') - let s:tmpname = substitute(s:tmpname, '/', '\\', 'g') + let tmpname = substitute(tmpname, '/', '\\', 'g') endif - if ! exists('s:patchreview_tmpfiles') - let s:patchreview_tmpfiles = [] - endif - let s:patchreview_tmpfiles = s:patchreview_tmpfiles + [s:tmpname] - let s:filterdiffcmd = '!' . g:patchreview_filterdiff . ' -i ' . s:RelativeFilePath . ' ' . s:PatchFilePath . ' > ' . s:tmpname - silent! exe s:filterdiffcmd - if s:filewithchangetype =~ '^+ ' - if has('win32') - let s:inputfile = 'nul' - else - let s:inputfile = '/dev/null' - endif + " write patch for patch.filename into tmpname + call writefile(patch.content, tmpname) + if patch.type == '+' && s:reviewmode == 'patch' + let inputfile = '' + let patchcmd = '!' . g:patchreview_patch . patch_R_option . ' -o "' . tmpname . '.file" "' . inputfile . '" < "' . tmpname . '"' + elseif patch.type == '+' && s:reviewmode == 'diff' + let inputfile = '' + unlet! patchcmd else - let s:inputfile = expand(s:RelativeFilePath, ':p') + let inputfile = expand(StrippedRelativeFilePath, ':p') + let patchcmd = '!' . g:patchreview_patch . patch_R_option . ' -o "' . tmpname . '.file" "' . inputfile . '" < "' . tmpname . '"' endif - silent exe '!' . g:patchreview_patch . ' -o ' . s:tmpname . '.file ' . s:inputfile . ' < ' . s:tmpname + if exists('patchcmd') + let v:errmsg = '' + Debug patchcmd + silent exe patchcmd + if v:errmsg != '' || v:shell_error + Pecho 'ERROR: Could not execute patch command.' + Pecho 'ERROR: ' . patchcmd + Pecho 'ERROR: ' . v:errmsg + Pecho 'ERROR: Diff skipped.' + continue + endif + endif let s:origtabpagenr = tabpagenr() - silent! exe 'tabedit ' . s:RelativeFilePath - silent! exe 'vert diffsplit ' . s:tmpname . '.file' - if filereadable(s:tmpname . '.file.rej') - silent! exe 'topleft 5split ' . s:tmpname . '.file.rej' - call s:PR_echo(s:msgtype . '*** REJECTED *** ' . s:RelativeFilePath, 1) + silent! exe 'tabedit ' . StrippedRelativeFilePath + if exists('patchcmd') + silent! exe 'vert diffsplit ' . tmpname . '.file' else - call s:PR_echo(s:msgtype . ' ' . s:RelativeFilePath, 1) + silent! exe 'vnew' + endif + if filereadable(tmpname . '.file.rej') + silent! exe 'topleft 5split ' . tmpname . '.file.rej' + Pecho msgtype . '*** REJECTED *** ' . relpath, 1 + else + Pecho msgtype . ' ' . relpath, 1 endif silent! exe 'tabn ' . s:origtabpagenr endfor - call s:PR_echo('-----') - call s:PR_echo('Done.') - let &shortmess = s:save_shortmess -"}}} + Pecho '-----' + Pecho 'Done.' + endfunction "}}} -function! <SID>PatchReviewCleanup() "{{{ - let s:retval = s:PR_GetTempDirLocation(1) - if s:retval && exists('g:patchreview_tmpdir') && isdirectory(g:patchreview_tmpdir) && filewritable(g:patchreview_tmpdir) - let s:zefilestr = globpath(g:patchreview_tmpdir, 'PatchReview.*') - let s:theFilesList = split(s:zefilestr, '\m[\r\n]\+') - for s:thefile in s:theFilesList - call delete(s:thefile) +function! <SID>PatchReviewCleanup() "{{{ + let retval = s:PR_GetTempDirLocation(1) + if retval && exists('g:patchreview_tmpdir') && isdirectory(g:patchreview_tmpdir) && filewritable(g:patchreview_tmpdir) + let zefilestr = globpath(g:patchreview_tmpdir, 'PatchReview.*') + let fileslist = split(zefilestr, '\m[\r\n]\+') + for thefile in fileslist + call delete(thefile) endfor endif endfunction "}}} -" Commands "{{{ +function! <SID>DiffReview(...) "{{{ + let s:save_shortmess = &shortmess + set shortmess=aW + call s:PR_wipeMsgBuf() + + let vcsdict = { + \'Mercurial' : {'dir' : '.hg', 'binary' : 'hg', 'diffargs' : 'diff' , 'strip' : 1}, + \'Bazaar-NG' : {'dir' : '.bzr', 'binary' : 'bzr', 'diffargs' : 'diff' , 'strip' : 0}, + \'monotone' : {'dir' : '_MTN', 'binary' : 'mtn', 'diffargs' : 'diff --unified', 'strip' : 0}, + \'Subversion' : {'dir' : '.svn', 'binary' : 'svn', 'diffargs' : 'diff' , 'strip' : 0}, + \'cvs' : {'dir' : 'CVS', 'binary' : 'cvs', 'diffargs' : '-q diff -u' , 'strip' : 0}, + \} + + unlet! s:theDiffCmd + unlet! l:vcs + if ! exists('g:patchreview_diffcmd') + for key in keys(vcsdict) + if isdirectory(vcsdict[key]['dir']) + if ! s:PR_checkBinary(vcsdict[key]['binary']) + Pecho 'Current directory looks like a ' . vcsdict[key] . ' repository but ' . vcsdist[key]['binary'] . ' command was not found on path.' + let &shortmess = s:save_shortmess + return + else + let s:theDiffCmd = vcsdict[key]['binary'] . ' ' . vcsdict[key]['diffargs'] + let strip = vcsdict[key]['strip'] + + Pecho 'Using [' . s:theDiffCmd . '] to generate diffs for this ' . key . ' review.' + let &shortmess = s:save_shortmess + let l:vcs = vcsdict[key]['binary'] + break + endif + else + continue + endif + endfor + else + let s:theDiffCmd = g:patchreview_diffcmd + let strip = 0 + endif + if ! exists('s:theDiffCmd') + Pecho 'Please define g:patchreview_diffcmd and make sure you are in a VCS controlled top directory.' + let &shortmess = s:save_shortmess + return + endif + + let retval = s:PR_GetTempDirLocation(0) + if ! retval + Pecho 'DiffReview aborted.' + let &shortmess = s:save_shortmess + return + endif + let outfile = g:patchreview_tmpdir . 'PatchReview.diff.' . strftime('%Y%m%d%H%M%S') + let cmd = '!' . s:theDiffCmd . ' > "' . outfile . '"' + let v:errmsg = '' + silent exe cmd + if v:errmsg == '' && exists('l:vcs') && l:vcs == 'cvs' && v:shell_error == 1 + " Ignoring CVS non-error + elseif v:errmsg != '' || v:shell_error + Pecho 'Could not execute [' . s:theDiffCmd . ']' + Pecho v:errmsg + Pecho 'Diff review aborted.' + let &shortmess = s:save_shortmess + return + endif + let s:reviewmode = 'diff' + call s:_GenericReview([outfile, strip]) + let &shortmess = s:save_shortmess +endfunction +"}}} + +" End user commands "{{{ "============================================================================ " :PatchReview command! -nargs=* -complete=file PatchReview call s:PatchReview (<f-args>) +" :DiffReview +command! -nargs=0 DiffReview call s:DiffReview() " :PatchReviewCleanup command! -nargs=0 PatchReviewCleanup call s:PatchReviewCleanup () -"}}} +command! -nargs=0 DiffReviewCleanup call s:PatchReviewCleanup () "}}} -" vim: textwidth=78 nowrap tabstop=2 shiftwidth=2 softtabstop=2 expandtab -" vim: filetype=vim encoding=latin1 fileformat=unix foldlevel=0 foldmethod=marker +" Development "{{{ +if exists('g:patchreview_debug') + " Tests + function! <SID>PRExtractTestNative(...) + "let patchfiles = glob(expand(a:1) . '/?*') + "for fname in split(patchfiles) + call s:PR_wipeMsgBuf() + let fname = a:1 + call s:ExtractDiffsNative(fname) + for patch in g:patches['patch'] + for line in patch.content + Pecho line + endfor + endfor + "endfor + endfunction + + function! <SID>PRExtractTestVim(...) + "let patchfiles = glob(expand(a:1) . '/?*') + "for fname in split(patchfiles) + call s:PR_wipeMsgBuf() + let fname = a:1 + call s:ExtractDiffsPureVim(fname) + for patch in g:patches['patch'] + for line in patch.content + Pecho line + endfor + endfor + "endfor + endfunction + + command! -nargs=+ -complete=file PRTestVim call s:PRExtractTestVim(<f-args>) + command! -nargs=+ -complete=file PRTestNative call s:PRExtractTestNative(<f-args>) +endif "}}} + +" modeline +" vim: set et fdl=0 fdm=marker fenc=latin ff=unix ft=vim sw=2 sts=0 ts=2 textwidth=78 nowrap :
--- a/hgext/gpg.py Wed Feb 24 19:47:51 2010 +0100 +++ b/hgext/gpg.py Thu Feb 25 17:06:32 2010 +0100 @@ -6,7 +6,7 @@ '''commands to sign and verify changesets''' import os, tempfile, binascii -from mercurial import util, commands, match, cmdutil +from mercurial import util, commands, match from mercurial import node as hgnode from mercurial.i18n import _ @@ -237,7 +237,7 @@ repo.opener("localsigs", "ab").write(sigmessage) return - msigs = cmdutil.matchfiles(repo, ['.hgsigs']) + msigs = match.exact(repo.root, '', ['.hgsigs']) s = repo.status(match=msigs, unknown=True, ignored=True)[:6] if util.any(s) and not opts["force"]: raise util.Abort(_("working copy of .hgsigs is changed "
--- a/hgext/progress.py Wed Feb 24 19:47:51 2010 +0100 +++ b/hgext/progress.py Thu Feb 25 17:06:32 2010 +0100 @@ -170,6 +170,10 @@ sharedprog = None def uisetup(ui): + # Apps that derive a class from ui.ui() can use + # setconfig('progress', 'disable', 'True') to disable this extension + if ui.configbool('progress', 'disable'): + return if ui.interactive() and not ui.debugflag and not ui.quiet: # we instantiate one globally shared progress bar to avoid # competing progress bars when multiple UI objects get created
--- a/mercurial/commands.py Wed Feb 24 19:47:51 2010 +0100 +++ b/mercurial/commands.py Thu Feb 25 17:06:32 2010 +0100 @@ -3334,7 +3334,8 @@ _('do not prompt, assume \'yes\' for any required answers')), ('q', 'quiet', None, _('suppress output')), ('v', 'verbose', None, _('enable additional output')), - ('', 'config', [], _('set/override config option')), + ('', 'config', [], + _('set/override config option (use \'section.name=value\')')), ('', 'debug', None, _('enable debugging output')), ('', 'debugger', None, _('start debugger')), ('', 'encoding', encoding.encoding, _('set the charset encoding')),
--- a/mercurial/httprepo.py Wed Feb 24 19:47:51 2010 +0100 +++ b/mercurial/httprepo.py Thu Feb 25 17:06:32 2010 +0100 @@ -239,7 +239,8 @@ except ValueError, err: raise error.ResponseError( _('push failed (unexpected response):'), resp) - self.ui.write(output) + for l in output.splitlines(True): + self.ui.status(_('remote: '), l) return ret except socket.error, err: if err[0] in (errno.ECONNRESET, errno.EPIPE):
--- a/mercurial/localrepo.py Wed Feb 24 19:47:51 2010 +0100 +++ b/mercurial/localrepo.py Thu Feb 25 17:06:32 2010 +0100 @@ -622,16 +622,19 @@ finally: release(lock, wlock) - def invalidate(self): - for a in "changelog manifest".split(): - if a in self.__dict__: - delattr(self, a) + def invalidatecaches(self): self._tags = None self._tagtypes = None self.nodetagscache = None self._branchcache = None # in UTF-8 self._branchcachetip = None + def invalidate(self): + for a in "changelog manifest".split(): + if a in self.__dict__: + delattr(self, a) + self.invalidatecaches() + def _lock(self, lockname, wait, releasefn, acquirefn, desc): try: l = lock.lock(lockname, 0, releasefn, desc=desc) @@ -957,7 +960,7 @@ # head, refresh the tag cache, then immediately add a new head. # But I think doing it this way is necessary for the "instant # tag cache retrieval" case to work. - tags_.findglobaltags(self.ui, self, {}, {}) + self.invalidatecaches() def walk(self, match, node=None): '''
--- a/tests/test-branchmap.out Wed Feb 24 19:47:51 2010 +0100 +++ b/tests/test-branchmap.out Thu Feb 25 17:06:32 2010 +0100 @@ -17,10 +17,10 @@ pushing to http://localhost:PORT searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files +remote: adding changesets +remote: adding manifests +remote: adding file changes +remote: added 1 changesets with 1 changes to 1 files changeset: 1:58e7c90d67cb branch: æ tag: tip
--- a/tests/test-extension.out Wed Feb 24 19:47:51 2010 +0100 +++ b/tests/test-extension.out Thu Feb 25 17:06:32 2010 +0100 @@ -56,7 +56,7 @@ -y --noninteractive do not prompt, assume 'yes' for any required answers -q --quiet suppress output -v --verbose enable additional output - --config set/override config option + --config set/override config option (use 'section.name=value') --debug enable debugging output --debugger start debugger --encoding set the charset encoding (default: ascii) @@ -82,7 +82,7 @@ -y --noninteractive do not prompt, assume 'yes' for any required answers -q --quiet suppress output -v --verbose enable additional output - --config set/override config option + --config set/override config option (use 'section.name=value') --debug enable debugging output --debugger start debugger --encoding set the charset encoding (default: ascii)
--- a/tests/test-help.out Wed Feb 24 19:47:51 2010 +0100 +++ b/tests/test-help.out Thu Feb 25 17:06:32 2010 +0100 @@ -220,7 +220,7 @@ -y --noninteractive do not prompt, assume 'yes' for any required answers -q --quiet suppress output -v --verbose enable additional output - --config set/override config option + --config set/override config option (use 'section.name=value') --debug enable debugging output --debugger start debugger --encoding set the charset encoding (default: ascii) @@ -288,7 +288,7 @@ -y --noninteractive do not prompt, assume 'yes' for any required answers -q --quiet suppress output -v --verbose enable additional output - --config set/override config option + --config set/override config option (use 'section.name=value') --debug enable debugging output --debugger start debugger --encoding set the charset encoding (default: ascii)
--- a/tests/test-push-http.out Wed Feb 24 19:47:51 2010 +0100 +++ b/tests/test-push-http.out Thu Feb 25 17:06:32 2010 +0100 @@ -4,7 +4,7 @@ % expect ssl error pushing to http://localhost:$HGPORT/ searching for changes -ssl required +remote: ssl required % serve errors % expect authorization error abort: authorization failed @@ -19,10 +19,10 @@ % expect success pushing to http://localhost:$HGPORT/ searching for changes -adding changesets -adding manifests -adding file changes -added 1 changesets with 1 changes to 1 files +remote: adding changesets +remote: adding manifests +remote: adding file changes +remote: added 1 changesets with 1 changes to 1 files % serve errors changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http rolling back last transaction
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-cache Thu Feb 25 17:06:32 2010 +0100 @@ -0,0 +1,104 @@ +#!/bin/sh + +createrepo() { + rm -rf repo + hg init repo + cd repo + + echo "a" > a + hg commit -d '0 0' -A -m 'A' + + hg branch branch1 + hg commit -d '1 0' -m 'Branch1' + + echo "b" > b + hg commit -A -d '2 0' -m 'B' + + hg up 0 + hg branch branch2 + hg commit -d '3 0' -m 'Branch2' + + echo "c" > C + hg commit -A -d '4 0' -m 'C' + + hg up 2 + hg branch -f branch2 + echo "d" > d + hg commit -A -d '5 0' -m 'D' + + echo "e" > e + hg commit -A -d '6 0' -m 'E' + + hg update default + + hg branch branch3 + hg commit -d '7 0' -m 'Branch3' + + echo "f" > f + hg commit -A -d '8 0' -m 'F' +} + +echo +createrepo > /dev/null 2>&1 +hg --config extensions.hgext.graphlog= glog --template '{rev}:{node|short} {desc} branch: {branches}\n' + +echo +echo '% Branches' +hg branches + +echo +echo '% Heads' +hg heads --template '{rev}:{node|short} {desc} branch: {branches}\n' + +echo +echo '% Rebase part of branch2 (5-6) onto branch3 (8)' +hg --config extensions.hgext.rebase= rebase --detach -s 5 -d 8 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +echo +echo '% Branches' +hg branches + +echo +echo '% Heads' +hg heads --template '{rev}:{node|short} {desc} branch: {branches}\n' + +echo +hg --config extensions.hgext.graphlog= glog --template '{rev}:{node|short} {desc} branch: {branches}\n' + +echo +echo '% Rebase head of branch3 (8) onto branch2 (6)' +createrepo > /dev/null 2>&1 +hg --config extensions.hgext.graphlog= glog --template '{rev}:{node|short} {desc} branch: {branches}\n' + +hg --config extensions.hgext.rebase= rebase --detach -s 8 -d 6 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +echo +echo '% Branches' +hg branches + +echo +echo '% Heads' +hg heads --template '{rev}:{node|short} {desc} branch: {branches}\n' + +echo +hg --config extensions.hgext.graphlog= glog --template '{rev}:{node|short} {desc} branch: {branches}\n' +hg verify -q + +echo +echo '% Rebase entire branch3 (7-8) onto branch2 (6)' +createrepo > /dev/null 2>&1 +hg --config extensions.hgext.graphlog= glog --template '{rev}:{node|short} {desc} branch: {branches}\n' + +hg --config extensions.hgext.rebase= rebase --detach -s 7 -d 6 2>&1 | sed 's/\(saving bundle to \).*/\1/' + +echo +echo '% Branches' +hg branches + +echo +echo '% Heads' +hg heads --template '{rev}:{node|short} {desc} branch: {branches}\n' + +echo +hg --config extensions.hgext.graphlog= glog --template '{rev}:{node|short} {desc} branch: {branches}\n' +hg verify -q
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rebase-cache.out Thu Feb 25 17:06:32 2010 +0100 @@ -0,0 +1,186 @@ + +@ 8:c11d5b3e9c00 F branch: branch3 +| +o 7:33c9da881988 Branch3 branch: branch3 +| +| o 6:0e4064ab11a3 E branch: branch2 +| | +| o 5:5ac035cb5d8f D branch: branch2 +| | +| | o 4:8e66061486ee C branch: branch2 +| | | ++---o 3:99567862abbe Branch2 branch: branch2 +| | +| o 2:65a26a4d12f6 B branch: branch1 +| | +| o 1:0f3f3010ee16 Branch1 branch: branch1 +|/ +o 0:1994f17a630e A branch: + + +% Branches +branch3 8:c11d5b3e9c00 +branch2 6:0e4064ab11a3 +branch1 2:65a26a4d12f6 (inactive) +default 0:1994f17a630e (inactive) + +% Heads +8:c11d5b3e9c00 F branch: branch3 +6:0e4064ab11a3 E branch: branch2 +4:8e66061486ee C branch: branch2 +2:65a26a4d12f6 B branch: branch1 +0:1994f17a630e A branch: + +% Rebase part of branch2 (5-6) onto branch3 (8) +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 4 changesets with 3 changes to 3 files (+1 heads) +rebase completed + +% Branches +branch3 8:c9bfa9beb84e +branch2 4:8e66061486ee +branch1 2:65a26a4d12f6 +default 0:1994f17a630e (inactive) + +% Heads +8:c9bfa9beb84e E branch: branch3 +4:8e66061486ee C branch: branch2 +2:65a26a4d12f6 B branch: branch1 +0:1994f17a630e A branch: + +@ 8:c9bfa9beb84e E branch: branch3 +| +o 7:bf9037384081 D branch: branch3 +| +o 6:c11d5b3e9c00 F branch: branch3 +| +o 5:33c9da881988 Branch3 branch: branch3 +| +| o 4:8e66061486ee C branch: branch2 +| | +| o 3:99567862abbe Branch2 branch: branch2 +|/ +| o 2:65a26a4d12f6 B branch: branch1 +| | +| o 1:0f3f3010ee16 Branch1 branch: branch1 +|/ +o 0:1994f17a630e A branch: + + +% Rebase head of branch3 (8) onto branch2 (6) +@ 8:c11d5b3e9c00 F branch: branch3 +| +o 7:33c9da881988 Branch3 branch: branch3 +| +| o 6:0e4064ab11a3 E branch: branch2 +| | +| o 5:5ac035cb5d8f D branch: branch2 +| | +| | o 4:8e66061486ee C branch: branch2 +| | | ++---o 3:99567862abbe Branch2 branch: branch2 +| | +| o 2:65a26a4d12f6 B branch: branch1 +| | +| o 1:0f3f3010ee16 Branch1 branch: branch1 +|/ +o 0:1994f17a630e A branch: + +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +rebase completed + +% Branches +branch2 8:b44d3024f247 +branch3 7:33c9da881988 +branch1 2:65a26a4d12f6 (inactive) +default 0:1994f17a630e (inactive) + +% Heads +8:b44d3024f247 F branch: branch2 +7:33c9da881988 Branch3 branch: branch3 +4:8e66061486ee C branch: branch2 +2:65a26a4d12f6 B branch: branch1 +0:1994f17a630e A branch: + +@ 8:b44d3024f247 F branch: branch2 +| +| o 7:33c9da881988 Branch3 branch: branch3 +| | +o | 6:0e4064ab11a3 E branch: branch2 +| | +o | 5:5ac035cb5d8f D branch: branch2 +| | +| | o 4:8e66061486ee C branch: branch2 +| | | +| | o 3:99567862abbe Branch2 branch: branch2 +| |/ +o | 2:65a26a4d12f6 B branch: branch1 +| | +o | 1:0f3f3010ee16 Branch1 branch: branch1 +|/ +o 0:1994f17a630e A branch: + + +% Rebase entire branch3 (7-8) onto branch2 (6) +@ 8:c11d5b3e9c00 F branch: branch3 +| +o 7:33c9da881988 Branch3 branch: branch3 +| +| o 6:0e4064ab11a3 E branch: branch2 +| | +| o 5:5ac035cb5d8f D branch: branch2 +| | +| | o 4:8e66061486ee C branch: branch2 +| | | ++---o 3:99567862abbe Branch2 branch: branch2 +| | +| o 2:65a26a4d12f6 B branch: branch1 +| | +| o 1:0f3f3010ee16 Branch1 branch: branch1 +|/ +o 0:1994f17a630e A branch: + +saving bundle to +adding branch +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +rebase completed + +% Branches +branch2 7:b44d3024f247 +branch1 2:65a26a4d12f6 (inactive) +default 0:1994f17a630e (inactive) + +% Heads +7:b44d3024f247 F branch: branch2 +4:8e66061486ee C branch: branch2 +2:65a26a4d12f6 B branch: branch1 +0:1994f17a630e A branch: + +@ 7:b44d3024f247 F branch: branch2 +| +o 6:0e4064ab11a3 E branch: branch2 +| +o 5:5ac035cb5d8f D branch: branch2 +| +| o 4:8e66061486ee C branch: branch2 +| | +| o 3:99567862abbe Branch2 branch: branch2 +| | +o | 2:65a26a4d12f6 B branch: branch1 +| | +o | 1:0f3f3010ee16 Branch1 branch: branch1 +|/ +o 0:1994f17a630e A branch: +