# HG changeset patch # User Matt Mackall # Date 1235744022 21600 # Node ID 6d99ff7b79b54f624eee18f2c1e3be6f6efed98a # Parent dd970a311ea863376414d77b3b680e206f75e96e# Parent e5627562b9f2ce6243bbf9a65291bf99562a73c0 Merge with stable diff -r dd970a311ea8 -r 6d99ff7b79b5 .hgignore --- a/.hgignore Sun Jan 25 19:15:49 2009 +0100 +++ b/.hgignore Fri Feb 27 08:13:42 2009 -0600 @@ -27,6 +27,16 @@ .DS_Store tags cscope.* +i18n/hg.pot +locale/*/LC_MESSAGES/hg.mo + +# files installed with a local --pure build +mercurial/base85.py +mercurial/bdiff.py +mercurial/diffhelpers.py +mercurial/mpatch.py +mercurial/osutil.py +mercurial/parsers.py syntax: regexp ^\.pc/ diff -r dd970a311ea8 -r 6d99ff7b79b5 Makefile --- a/Makefile Sun Jan 25 19:15:49 2009 +0100 +++ b/Makefile Fri Feb 27 08:13:42 2009 -0600 @@ -1,6 +1,7 @@ PREFIX=/usr/local export PREFIX PYTHON=python +PURE= help: @echo 'Commonly used make targets:' @@ -13,6 +14,7 @@ @echo ' dist - run all tests and create a source tarball in dist/' @echo ' clean - remove files created by other targets' @echo ' (except installed files or dist source tarball)' + @echo ' update-pot - update i18n/hg.pot' @echo @echo 'Example for a system-wide installation under /usr/local:' @echo ' make all && su -c "make install" && hg version' @@ -23,12 +25,11 @@ all: build doc local: - $(PYTHON) setup.py build_ext -i - $(PYTHON) setup.py build_py -c -d . + $(PYTHON) setup.py $(PURE) build_py -c -d . build_ext -i build_mo $(PYTHON) hg version build: - $(PYTHON) setup.py build + $(PYTHON) setup.py $(PURE) build doc: $(MAKE) -C doc @@ -37,12 +38,13 @@ -$(PYTHON) setup.py clean --all # ignore errors of this command find . -name '*.py[cdo]' -exec rm -f '{}' ';' rm -f MANIFEST mercurial/__version__.py mercurial/*.so tests/*.err + rm -rf locale $(MAKE) -C doc clean install: install-bin install-doc install-bin: build - $(PYTHON) setup.py install --prefix="$(PREFIX)" --force + $(PYTHON) setup.py $(PURE) install --prefix="$(PREFIX)" --force install-doc: doc cd doc && $(MAKE) $(MFLAGS) install @@ -50,7 +52,7 @@ install-home: install-home-bin install-home-doc install-home-bin: build - $(PYTHON) setup.py install --home="$(HOME)" --force + $(PYTHON) setup.py $(PURE) install --home="$(HOME)" --force install-home-doc: doc cd doc && $(MAKE) $(MFLAGS) PREFIX="$(HOME)" install @@ -74,6 +76,20 @@ test-%: cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) $@ +update-pot: + mkdir -p i18n + pygettext -d hg -p i18n --docstrings \ + mercurial/commands.py hgext/*.py hgext/*/__init__.py + # All strings marked for translation in Mercurial contain + # ASCII characters only. But some files contain string + # literals like this '\037\213'. xgettext thinks it has to + # parse these them even though they are not marked for + # translation. Extracting with an explicit encoding of + # ISO-8859-1 will make xgettext "parse" and ignore them. + find mercurial hgext doc -name '*.py' | xargs \ + xgettext --from-code ISO-8859-1 --join --sort-by-file \ + -d hg -p i18n -o hg.pot .PHONY: help all local build doc clean install install-bin install-doc \ - install-home install-home-bin install-home-doc dist dist-notests tests + install-home install-home-bin install-home-doc dist dist-notests tests \ + update-pot diff -r dd970a311ea8 -r 6d99ff7b79b5 contrib/hgk --- a/contrib/hgk Sun Jan 25 19:15:49 2009 +0100 +++ b/contrib/hgk Fri Feb 27 08:13:42 2009 -0600 @@ -265,6 +265,7 @@ proc parsecommit {id contents listed olds} { global commitinfo children nchildren parents nparents cdate ncleft + global firstparents set inhdr 1 set comment {} @@ -338,6 +339,33 @@ } set commitinfo($id) [list $headline $auname $audate \ $comname $comdate $comment $rev $branch] + + if {[info exists firstparents]} { + set i [lsearch $firstparents $id] + if {$i != -1} { + # remove the parent from firstparents, possible building + # an empty list + set firstparents [concat \ + [lrange $firstparents 0 [expr $i - 1]] \ + [lrange $firstparents [expr $i + 1] end]] + if {$firstparents eq {}} { + # we have found all parents of the first changeset + # which means that we can safely select the first line + after idle { + selectline 0 0 + } + } + } + } else { + # this is the first changeset, save the parents + set firstparents $olds + if {$firstparents eq {}} { + # a repository with a single changeset + after idle { + selectline 0 0 + } + } + } } proc readrefs {} { @@ -439,7 +467,8 @@ global entries sha1entry sha1string sha1but global maincursor textcursor curtextcursor global rowctxmenu gaudydiff mergemax - global hgvdiff + global hgvdiff bgcolor fgcolor diffremcolor diffaddcolor diffmerge1color + global diffmerge2color hunksepcolor menu .bar .bar add cascade -label "File" -menu .bar.file @@ -478,16 +507,16 @@ .ctop add .ctop.top set canv .ctop.top.clist.canv canvas $canv -height $geometry(canvh) -width $geometry(canv1) \ - -bg white -bd 0 \ + -bg $bgcolor -bd 0 \ -yscrollincr $linespc -yscrollcommand "$cscroll set" -selectbackground grey .ctop.top.clist add $canv set canv2 .ctop.top.clist.canv2 canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \ - -bg white -bd 0 -yscrollincr $linespc -selectbackground grey + -bg $bgcolor -bd 0 -yscrollincr $linespc -selectbackground grey .ctop.top.clist add $canv2 set canv3 .ctop.top.clist.canv3 canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \ - -bg white -bd 0 -yscrollincr $linespc -selectbackground grey + -bg $bgcolor -bd 0 -yscrollincr $linespc -selectbackground grey .ctop.top.clist add $canv3 bind .ctop.top.clist {resizeclistpanes %W %w} @@ -547,7 +576,7 @@ .ctop add .ctop.cdet frame .ctop.cdet.left set ctext .ctop.cdet.left.ctext - text $ctext -bg white -state disabled -font $textfont \ + text $ctext -fg $fgcolor -bg $bgcolor -state disabled -font $textfont \ -width $geometry(ctextw) -height $geometry(ctexth) \ -yscrollcommand ".ctop.cdet.left.sb set" \ -xscrollcommand ".ctop.cdet.left.hb set" -wrap none @@ -564,11 +593,16 @@ $ctext tag conf d0 -back "#ff8080" $ctext tag conf d1 -back green } else { - $ctext tag conf hunksep -fore blue - $ctext tag conf d0 -fore red - $ctext tag conf d1 -fore "#00a000" - $ctext tag conf m0 -fore red - $ctext tag conf m1 -fore blue + $ctext tag conf hunksep -fore $hunksepcolor + $ctext tag conf d0 -fore $diffremcolor + $ctext tag conf d1 -fore $diffaddcolor + + # The mX colours seem to be used in merge changesets, where m0 + # is first parent, m1 is second parent and so on. Git can have + # several parents, Hg cannot, so I think the m2..mmax would be + # unused. + $ctext tag conf m0 -fore $diffmerge1color + $ctext tag conf m1 -fore $diffmerge2color $ctext tag conf m2 -fore green $ctext tag conf m3 -fore purple $ctext tag conf m4 -fore brown @@ -581,7 +615,8 @@ frame .ctop.cdet.right set cflist .ctop.cdet.right.cfiles - listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \ + listbox $cflist -fg $fgcolor -bg $bgcolor \ + -selectmode extended -width $geometry(cflistw) \ -yscrollcommand ".ctop.cdet.right.sb set" scrollbar .ctop.cdet.right.sb -command "$cflist yview" pack .ctop.cdet.right.sb -side right -fill y @@ -679,7 +714,9 @@ proc savestuff {w} { global canv canv2 canv3 ctext cflist mainfont textfont global stuffsaved findmergefiles gaudydiff maxgraphpct - global maxwidth authorcolors curidfont + global maxwidth authorcolors curidfont bgcolor fgcolor + global diffremcolor diffaddcolor hunksepcolor + global diffmerge1color diffmerge2color if {$stuffsaved} return if {![winfo viewable .]} return @@ -721,6 +758,27 @@ puts $f "# the last entry will be reused." puts $f "#" puts $f "set authorcolors {$authorcolors}" + puts $f "#" + puts $f "# The background color in the text windows" + puts $f "set bgcolor $bgcolor" + puts $f "#" + puts $f "# The text color used in the diff and file list view" + puts $f "set fgcolor $fgcolor" + puts $f "#" + puts $f "# Color to display + lines in diffs" + puts $f "set diffaddcolor $diffaddcolor" + puts $f "#" + puts $f "# Color to display - lines in diffs" + puts $f "set diffremcolor $diffremcolor" + puts $f "#" + puts $f "# Merge diffs: Color to signal lines from first parent" + puts $f "set diffmerge1color $diffmerge1color" + puts $f "#" + puts $f "# Merge diffs: Color to signal lines from second parent" + puts $f "set diffmerge2color $diffmerge2color" + puts $f "#" + puts $f "# Hunkseparator (@@ -lineno,lines +lineno,lines @@) color" + puts $f "set hunksepcolor $hunksepcolor" close $f file rename -force "~/.hgk-new" "~/.hgk" } @@ -3891,6 +3949,16 @@ set authorcolors { black blue deeppink mediumorchid blue burlywood4 goldenrod slateblue red2 navy dimgrey } +set bgcolor white + +# This color should probably be some system color (provided by tk), +# but as the bgcolor has always been set to white, I choose to ignore +set fgcolor black +set diffaddcolor "#00a000" +set diffremcolor red +set diffmerge1color red +set diffmerge2color blue +set hunksepcolor blue catch {source ~/.hgk} diff -r dd970a311ea8 -r 6d99ff7b79b5 contrib/hgwebdir.fcgi --- a/contrib/hgwebdir.fcgi Sun Jan 25 19:15:49 2009 +0100 +++ b/contrib/hgwebdir.fcgi Fri Feb 27 08:13:42 2009 -0600 @@ -22,7 +22,6 @@ #os.environ["HGENCODING"] = "UTF-8" from mercurial.hgweb.hgwebdir_mod import hgwebdir -from mercurial.hgweb.request import wsgiapplication from flup.server.fcgi import WSGIServer # The config file looks like this. You can have paths to individual @@ -60,7 +59,4 @@ # Alternatively you can pass a list of ('virtual/path', '/real/path') tuples # or use a dictionary with entries like 'virtual/path': '/real/path' -def make_web_app(): - return hgwebdir("hgweb.config") - -WSGIServer(wsgiapplication(make_web_app)).run() +WSGIServer(hgwebdir('hgweb.config')).run() diff -r dd970a311ea8 -r 6d99ff7b79b5 contrib/hgwebdir.wsgi --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/hgwebdir.wsgi Fri Feb 27 08:13:42 2009 -0600 @@ -0,0 +1,51 @@ +# An example WSGI (use with mod_wsgi) script to export multiple hgweb repos + +# adjust python path if not a system-wide install: +#import sys +#sys.path.insert(0, "/path/to/python/lib") + +# enable demandloading to reduce startup time +from mercurial import demandimport; demandimport.enable() +from mercurial.hgweb.hgwebdir_mod import hgwebdir + +# If you'd like to serve pages with UTF-8 instead of your default +# locale charset, you can do so by uncommenting the following lines. +# Note that this will cause your .hgrc files to be interpreted in +# UTF-8 and all your repo files to be displayed using UTF-8. +# +#import os +#os.environ["HGENCODING"] = "UTF-8" + +# The config file looks like this. You can have paths to individual +# repos, collections of repos in a directory tree, or both. +# +# [paths] +# virtual/path1 = /real/path1 +# virtual/path2 = /real/path2 +# virtual/root = /real/root/* +# / = /real/root2/* +# +# paths example: +# +# * First two lines mount one repository into one virtual path, like +# '/real/path1' into 'virtual/path1'. +# +# * The third entry tells every mercurial repository found in +# '/real/root', recursively, should be mounted in 'virtual/root'. This +# format is preferred over the [collections] one, using absolute paths +# as configuration keys is not supported on every platform (including +# Windows). +# +# * The last entry is a special case mounting all repositories in +# '/real/root2' in the root of the virtual directory. +# +# collections example: say directory tree /foo contains repos /foo/bar, +# /foo/quux/baz. Give this config section: +# [collections] +# /foo = /foo +# Then repos will list as bar and quux/baz. +# +# Alternatively you can pass a list of ('virtual/path', '/real/path') tuples +# or use a dictionary with entries like 'virtual/path': '/real/path' + +application = hgwebdir('hgweb.config') diff -r dd970a311ea8 -r 6d99ff7b79b5 contrib/mergetools.hgrc --- a/contrib/mergetools.hgrc Sun Jan 25 19:15:49 2009 +0100 +++ b/contrib/mergetools.hgrc Fri Feb 27 08:13:42 2009 -0600 @@ -38,8 +38,9 @@ p4merge.gui=True p4merge.priority=-8 -tortoisemerge.args=/base: $output /mine:$local /theirs:$other /merged:$output +tortoisemerge.args=/base:$base /mine:$local /theirs:$other /merged:$output tortoisemerge.regkey=Software\TortoiseSVN +tortoisemerge.checkchanged=True tortoisemerge.gui=True ecmerge.args=$base $local $other --mode=merge3 --title0=base --title1=local --title2=other --to=$output @@ -49,3 +50,14 @@ filemerge.executable=/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge filemerge.args=-left $other -right $local -ancestor $base -merge $output filemerge.gui=True + +beyondcompare3.args=$local $other $base $output /ro /lefttitle=local /centerfile=base /righttitle=other /automerge /reviewconflicts /solo +beyondcompare3.regkey=Software\Scooter Software\Beyond Compare 3 +beyondcompare3.regname=ExePath +beyondcompare3.gui=True + +winmerge.args=/e /u /dl local /dr other /wr $local $other $output +winmerge.regkey=Software\Thingamahoochie\WinMerge +winmerge.regname=Executable +winmerge.checkchanged=True +winmerge.gui=True diff -r dd970a311ea8 -r 6d99ff7b79b5 contrib/tcsh_completion --- a/contrib/tcsh_completion Sun Jan 25 19:15:49 2009 +0100 +++ b/contrib/tcsh_completion Fri Feb 27 08:13:42 2009 -0600 @@ -2,7 +2,7 @@ # tcsh completion for Mercurial # # This file has been auto-generated by tcsh_completion_build.sh for -# Mercurial Distributed SCM (version 325c07fd2ebd) +# Mercurial Distributed SCM (version 1.1.2) # # Copyright (C) 2005 TK Soh. # @@ -19,24 +19,31 @@ -y --noninteractive \ -q --quiet \ -v --verbose \ + --config \ --debug \ --debugger \ + --encoding \ + --encodingmode \ + --lsprof \ --traceback \ --time \ --profile \ --version \ -h --help)/' \ - 'p/1/(add addremove annotate bundle cat \ - clone commit ci copy cp \ - debugancestor debugcheckstate debugconfig debugdata debugindex \ - debugindexdot debugrename debugstate debugwalk diff \ - export forget grep heads help \ - identify id import patch incoming \ - in init locate log history \ - manifest outgoing out parents paths \ - pull push rawcommit recover remove \ - rm rename mv revert root \ - serve status tag tags tip \ - unbundle undo update up checkout \ - co verify version)/' + 'p/1/(add addremove annotate blame archive \ + backout bisect branch branches bundle \ + cat clone commit ci copy \ + cp debugancestor debugcheckstate debugcomplete debugdata \ + debugdate debugfsinfo debugindex debugindexdot debuginstall \ + debugrawcommit rawcommit debugrebuildstate debugrename debugsetparents \ + debugstate debugwalk diff export grep \ + heads help identify id import \ + patch incoming in init locate \ + log history manifest merge outgoing \ + out parents paths pull push \ + recover remove rm rename mv \ + resolve revert rollback root serve \ + showconfig debugconfig status st tag \ + tags tip unbundle update up \ + checkout co verify version)/' diff -r dd970a311ea8 -r 6d99ff7b79b5 contrib/tcsh_completion_build.sh --- a/contrib/tcsh_completion_build.sh Sun Jan 25 19:15:49 2009 +0100 +++ b/contrib/tcsh_completion_build.sh Fri Feb 27 08:13:42 2009 -0600 @@ -37,7 +37,7 @@ hg_commands=`hg --debug help | \ sed -e '1,/^list of commands:/d' \ - -e '/^global options:/,$d' \ + -e '/^enabled extensions:/,$d' \ -e '/^ [^ ]/!d; s/[,:]//g;' | \ xargs -n5 | \ sed -e '$!s/$/ \\\\/g; 2,$s/^ */ /g'` diff -r dd970a311ea8 -r 6d99ff7b79b5 contrib/win32/mercurial.ini --- a/contrib/win32/mercurial.ini Sun Jan 25 19:15:49 2009 +0100 +++ b/contrib/win32/mercurial.ini Fri Feb 27 08:13:42 2009 -0600 @@ -5,6 +5,13 @@ [ui] editor = notepad +; show changed files and be a bit more verbose if True +; verbose = True + +; username data to appear in commits +; it usually takes the form: Joe User +; username = Joe User + ; By default, we try to encode and decode all files that do not ; contain ASCII NUL characters. What this means is that we try to set @@ -37,5 +44,10 @@ ; Alternatively, you can explicitly specify each file extension that ; you want decoded (any you omit will be left untouched), like this: +; **.txt = dumbdecode: +[hgk] +; Replace the following with your path to hgk, uncomment it and +; install ActiveTcl (or another win32 port) +; path="C:\Program Files\Mercurial\Contrib\hgk.tcl" -; **.txt = dumbdecode: + diff -r dd970a311ea8 -r 6d99ff7b79b5 contrib/win32/mercurial.iss --- a/contrib/win32/mercurial.iss Sun Jan 25 19:15:49 2009 +0100 +++ b/contrib/win32/mercurial.iss Fri Feb 27 08:13:42 2009 -0600 @@ -1,8 +1,7 @@ ; Script generated by the Inno Setup Script Wizard. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - [Setup] -AppCopyright=Copyright 2005-2008 Matt Mackall and others +AppCopyright=Copyright 2005-2009 Matt Mackall and others AppName=Mercurial AppVerName=Mercurial snapshot InfoAfterFile=contrib/win32/postinstall.txt @@ -18,7 +17,7 @@ DefaultDirName={pf}\Mercurial SourceDir=..\.. VersionInfoDescription=Mercurial distributed SCM -VersionInfoCopyright=Copyright 2005-2008 Matt Mackall and others +VersionInfoCopyright=Copyright 2005-2009 Matt Mackall and others VersionInfoCompany=Matt Mackall and others InternalCompressLevel=max SolidCompression=true @@ -31,8 +30,10 @@ Source: contrib\mercurial.el; DestDir: {app}/Contrib Source: contrib\vim\*.*; DestDir: {app}/Contrib/Vim Source: contrib\zsh_completion; DestDir: {app}/Contrib +Source: contrib\hgk; DestDir: {app}/Contrib; DestName: hgk.tcl Source: contrib\win32\ReadMe.html; DestDir: {app}; Flags: isreadme -Source: contrib\win32\mercurial.ini; DestDir: {app}; DestName: Mercurial.ini; Flags: confirmoverwrite +Source: contrib\mergetools.hgrc; DestDir: {tmp}; +Source: contrib\win32\mercurial.ini; DestDir: {app}; DestName: Mercurial.ini; Check: CheckFile; AfterInstall: ConcatenateFiles; Source: contrib\win32\postinstall.txt; DestDir: {app}; DestName: ReleaseNotes.txt Source: dist\hg.exe; DestDir: {app}; AfterInstall: Touch('{app}\hg.exe.local') Source: dist\library.zip; DestDir: {app} @@ -64,8 +65,32 @@ [UninstallDelete] Type: files; Name: "{app}\hg.exe.local" +[Code] +var + WriteFile: Boolean; + CheckDone: Boolean; -[Code] +function CheckFile(): Boolean; +begin + if not CheckDone then begin + WriteFile := True; + if FileExists(ExpandConstant(CurrentFileName)) then begin + WriteFile := MsgBox('' + ExpandConstant(CurrentFileName) + '' #13#13 'The file already exists.' #13#13 'Would you like Setup to overwrite it?', mbConfirmation, MB_YESNO) = idYes; + end; + CheckDone := True; + end; + Result := WriteFile; +end; + +procedure ConcatenateFiles(); +var + MergeConfigs: TArrayOfString; +begin + if LoadStringsFromFile(ExpandConstant('{tmp}\mergetools.hgrc'),MergeConfigs) then begin + SaveStringsToFile(ExpandConstant(CurrentFileName),MergeConfigs,True); + end; +end; + procedure Touch(fn: String); begin SaveStringToFile(ExpandConstant(fn), '', False); diff -r dd970a311ea8 -r 6d99ff7b79b5 contrib/zsh_completion --- a/contrib/zsh_completion Sun Jan 25 19:15:49 2009 +0100 +++ b/contrib/zsh_completion Fri Feb 27 08:13:42 2009 -0600 @@ -4,14 +4,13 @@ # it into your zsh function path (/usr/share/zsh/site-functions for # instance) # -# Copyright (C) 2005 Steve Borho +# Copyright (C) 2005-6 Steve Borho # Copyright (C) 2006-8 Brendan Cully # # This is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your # option) any later version. -# emulate -LR zsh setopt extendedglob @@ -118,27 +117,17 @@ typeset -ga _hg_cmd_list typeset -gA _hg_alias_list local hline cmd cmdalias - _call_program help hg --verbose help | while read -A hline + + _call_program hg hg debugcomplete -v 2>/dev/null | while read -A hline do - cmd="$hline[1]" - case $cmd in - *:) - cmd=${cmd%:} - _hg_cmd_list+=($cmd) - ;; - *,) - cmd=${cmd%,} - _hg_cmd_list+=($cmd) - integer i=2 - while (( i <= $#hline )) - do - cmdalias=${hline[$i]%(:|,)} - _hg_cmd_list+=($cmdalias) - _hg_alias_list+=($cmdalias $cmd) - (( i++ )) - done - ;; - esac + cmd=$hline[1] + _hg_cmd_list+=($cmd) + + for cmdalias in $hline[2,-1] + do + _hg_cmd_list+=($cmdalias) + _hg_alias_list+=($cmdalias $cmd) + done done } diff -r dd970a311ea8 -r 6d99ff7b79b5 doc/Makefile --- a/doc/Makefile Sun Jan 25 19:15:49 2009 +0100 +++ b/doc/Makefile Fri Feb 27 08:13:42 2009 -0600 @@ -3,7 +3,7 @@ HTML=$(SOURCES:%.txt=%.html) PREFIX=/usr/local MANDIR=$(PREFIX)/share/man -INSTALL=install -c +INSTALL=install -c -m 644 PYTHON=python ASCIIDOC=asciidoc diff -r dd970a311ea8 -r 6d99ff7b79b5 hg --- a/hg Sun Jan 25 19:15:49 2009 +0100 +++ b/hg Fri Feb 27 08:13:42 2009 -0600 @@ -8,7 +8,14 @@ # of the GNU General Public License, incorporated herein by reference. # enable importing on demand to reduce startup time -from mercurial import demandimport; demandimport.enable() +try: + from mercurial import demandimport; demandimport.enable() +except ImportError: + import sys + sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" % + ' '.join(sys.path)) + sys.stderr.write("(check your install and PYTHONPATH)\n") + sys.exit(-1) import sys import mercurial.util diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/alias.py --- a/hgext/alias.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/alias.py Fri Feb 27 08:13:42 2009 -0600 @@ -9,9 +9,8 @@ mycmd = cmd --args ''' -from mercurial.cmdutil import findcmd, UnknownCommand, AmbiguousCommand -from mercurial import commands from mercurial.i18n import _ +from mercurial import commands, cmdutil, error cmdtable = {} @@ -43,16 +42,16 @@ return try: - self._cmd = findcmd(self._target, commands.table, False)[1] + self._cmd = cmdutil.findcmd(self._target, commands.table, False)[1] if self._cmd == self: raise RecursiveCommand() if self._target in commands.norepo.split(' '): commands.norepo += ' %s' % self._name return - except UnknownCommand: + except error.UnknownCommand: msg = _('*** [alias] %s: command %s is unknown') % \ (self._name, self._target) - except AmbiguousCommand: + except error.AmbiguousCommand: msg = _('*** [alias] %s: command %s is ambiguous') % \ (self._name, self._target) except RecursiveCommand: diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/bookmarks.py --- a/hgext/bookmarks.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/bookmarks.py Fri Feb 27 08:13:42 2009 -0600 @@ -14,19 +14,26 @@ It is possible to use bookmark names in every revision lookup (e.g. hg merge, hg update). + +The bookmark extension offers the possiblity to have a more git-like experience +by adding the following configuration option to your .hgrc: + +[bookmarks] +track.current = True + +This will cause bookmarks to track the bookmark that you are currently on, and +just updates it. This is similar to git's approach of branching. ''' -from mercurial.commands import templateopts, hex, short from mercurial.i18n import _ -from mercurial import cmdutil, util, commands, changelog -from mercurial.node import nullid, nullrev -from mercurial.repo import RepoError -import mercurial, mercurial.localrepo, mercurial.repair, os +from mercurial.node import nullid, nullrev, hex, short +from mercurial import util, commands, localrepo, repair, extensions +import os def parse(repo): '''Parse .hg/bookmarks file and return a dictionary - Bookmarks are stored as {HASH}\s{NAME}\n (localtags format) values + Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values in the .hg/bookmarks file. They are read by the parse() method and returned as a dictionary with name => hash values. @@ -54,11 +61,55 @@ ''' if os.path.exists(repo.join('bookmarks')): util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks')) + if current(repo) not in refs: + setcurrent(repo, None) file = repo.opener('bookmarks', 'w+') - for refspec, node in refs.items(): + for refspec, node in refs.iteritems(): file.write("%s %s\n" % (hex(node), refspec)) file.close() +def current(repo): + '''Get the current bookmark + + If we use gittishsh branches we have a current bookmark that + we are on. This function returns the name of the bookmark. It + is stored in .hg/bookmarks.current + ''' + if repo._bookmarkcurrent: + return repo._bookmarkcurrent + mark = None + if os.path.exists(repo.join('bookmarks.current')): + file = repo.opener('bookmarks.current') + # No readline() in posixfile_nt, reading everything is cheap + mark = (file.readlines() or [''])[0] + if mark == '': + mark = None + file.close() + repo._bookmarkcurrent = mark + return mark + +def setcurrent(repo, mark): + '''Set the name of the bookmark that we are currently on + + Set the name of the bookmark that we are on (hg update ). + The name is recoreded in .hg/bookmarks.current + ''' + if current(repo) == mark: + return + + refs = parse(repo) + + # do not update if we do update to a rev equal to the current bookmark + if (mark not in refs and + current(repo) and refs[current(repo)] == repo.changectx('.').node()): + return + if mark not in refs: + mark = '' + file = repo.opener('bookmarks.current', 'w+') + file.write(mark) + file.close() + repo._bookmarkcurrent = mark + def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None): '''mercurial bookmarks @@ -85,6 +136,8 @@ raise util.Abort(_("new bookmark name required")) marks[mark] = marks[rename] del marks[rename] + if current(repo) == rename: + setcurrent(repo, mark) write(repo, marks) return @@ -121,7 +174,11 @@ ui.status("no bookmarks set\n") else: for bmark, n in marks.iteritems(): - prefix = (n == cur) and '*' or ' ' + if ui.configbool('bookmarks', 'track.current'): + prefix = (bmark == current(repo) and n == cur) and '*' or ' ' + else: + prefix = (n == cur) and '*' or ' ' + ui.write(" %s %-25s %d:%s\n" % ( prefix, bmark, repo.changelog.rev(n), hexfn(n))) return @@ -140,14 +197,14 @@ saveheads.append(p) return [r for r in tostrip if r not in saveheads] -def strip(ui, repo, node, backup="all"): +def strip(oldstrip, ui, repo, node, backup="all"): """Strip bookmarks if revisions are stripped using the mercurial.strip method. This usually happens during qpush and qpop""" revisions = _revstostrip(repo.changelog, node) marks = parse(repo) update = [] - for mark, n in marks.items(): + for mark, n in marks.iteritems(): if repo.changelog.rev(n) in revisions: update.append(mark) oldstrip(ui, repo, node, backup) @@ -156,16 +213,14 @@ marks[m] = repo.changectx('.').node() write(repo, marks) -oldstrip = mercurial.repair.strip -mercurial.repair.strip = strip - def reposetup(ui, repo): - if not isinstance(repo, mercurial.localrepo.localrepository): + if not isinstance(repo, localrepo.localrepository): return # init a bookmark cache as otherwise we would get a infinite reading # in lookup() repo._bookmarks = None + repo._bookmarkcurrent = None class bookmark_repo(repo.__class__): def rollback(self): @@ -192,9 +247,14 @@ marks = parse(repo) update = False for mark, n in marks.items(): - if n in parents: - marks[mark] = node - update = True + if ui.configbool('bookmarks', 'track.current'): + if mark == current(repo) and n in parents: + marks[mark] = node + update = True + else: + if n in parents: + marks[mark] = node + update = True if update: write(repo, marks) return node @@ -218,8 +278,35 @@ write(repo, marks) return result + def tags(self): + """Merge bookmarks with normal tags""" + if self.tagscache: + return self.tagscache + + tagscache = super(bookmark_repo, self).tags() + tagscache.update(parse(repo)) + return tagscache + repo.__class__ = bookmark_repo +def uisetup(ui): + extensions.wrapfunction(repair, "strip", strip) + if ui.configbool('bookmarks', 'track.current'): + extensions.wrapcommand(commands.table, 'update', updatecurbookmark) + +def updatecurbookmark(orig, ui, repo, *args, **opts): + '''Set the current bookmark + + If the user updates to a bookmark we update the .hg/bookmarks.current + file. + ''' + res = orig(ui, repo, *args, **opts) + rev = opts['rev'] + if not rev and len(args) > 0: + rev = args[0] + setcurrent(repo, rev) + return res + cmdtable = { "bookmarks": (bookmark, @@ -227,5 +314,5 @@ ('r', 'rev', '', _('revision')), ('d', 'delete', False, _('delete a given bookmark')), ('m', 'rename', '', _('rename a given bookmark'))], - _('hg bookmarks [-d] [-m NAME] [-r NAME] [NAME]')), + _('hg bookmarks [-f] [-d] [-m NAME] [-r NAME] [NAME]')), } diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/bugzilla.py --- a/hgext/bugzilla.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/bugzilla.py Fri Feb 27 08:13:42 2009 -0600 @@ -4,53 +4,111 @@ # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -# -# hook extension to update comments of bugzilla bugs when changesets -# that refer to bugs by id are seen. this hook does not change bug -# status, only comments. -# -# to configure, add items to '[bugzilla]' section of hgrc. -# -# to use, configure bugzilla extension and enable like this: -# -# [extensions] -# hgext.bugzilla = -# -# [hooks] -# # run bugzilla hook on every change pulled or pushed in here -# incoming.bugzilla = python:hgext.bugzilla.hook -# -# config items: -# -# section name is 'bugzilla'. -# [bugzilla] -# -# REQUIRED: -# host = bugzilla # mysql server where bugzilla database lives -# password = ** # user's password -# version = 2.16 # version of bugzilla installed -# -# OPTIONAL: -# bzuser = ... # fallback bugzilla user name to record comments with -# db = bugs # database to connect to -# notify = ... # command to run to get bugzilla to send mail -# regexp = ... # regexp to match bug ids (must contain one "()" group) -# strip = 0 # number of slashes to strip for url paths -# style = ... # style file to use when formatting comments -# template = ... # template to use when formatting comments -# timeout = 5 # database connection timeout (seconds) -# user = bugs # user to connect to database as -# [web] -# baseurl = http://hgserver/... # root of hg web site for browsing commits -# -# if hg committer names are not same as bugzilla user names, use -# "usermap" feature to map from committer email to bugzilla user name. -# usermap can be in hgrc or separate config file. -# -# [bugzilla] -# usermap = filename # cfg file with "committer"="bugzilla user" info -# [usermap] -# committer_email = bugzilla_user_name + +'''Bugzilla integration + +This hook extension adds comments on bugs in Bugzilla when changesets +that refer to bugs by Bugzilla ID are seen. The hook does not change bug +status. + +The hook updates the Bugzilla database directly. Only Bugzilla installations +using MySQL are supported. + +The hook relies on a Bugzilla script to send bug change notification emails. +That script changes between Bugzilla versions; the 'processmail' script used +prior to 2.18 is replaced in 2.18 and subsequent versions by +'config/sendbugmail.pl'. Note that these will be run by Mercurial as the user +pushing the change; you will need to ensure the Bugzilla install file +permissions are set appropriately. + +Configuring the extension: + + [bugzilla] + host Hostname of the MySQL server holding the Bugzilla database. + db Name of the Bugzilla database in MySQL. Default 'bugs'. + user Username to use to access MySQL server. Default 'bugs'. + password Password to use to access MySQL server. + timeout Database connection timeout (seconds). Default 5. + version Bugzilla version. Specify '3.0' for Bugzilla versions 3.0 and + later, '2.18' for Bugzilla versions from 2.18 and '2.16' for + versions prior to 2.18. + bzuser Fallback Bugzilla user name to record comments with, if + changeset committer cannot be found as a Bugzilla user. + bzdir Bugzilla install directory. Used by default notify. + Default '/var/www/html/bugzilla'. + notify The command to run to get Bugzilla to send bug change + notification emails. Substitutes from a map with 3 keys, + 'bzdir', 'id' (bug id) and 'user' (committer bugzilla email). + Default depends on version; from 2.18 it is + "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s". + regexp Regular expression to match bug IDs in changeset commit message. + Must contain one "()" group. The default expression matches + 'Bug 1234', 'Bug no. 1234', 'Bug number 1234', + 'Bugs 1234,5678', 'Bug 1234 and 5678' and variations thereof. + Matching is case insensitive. + style The style file to use when formatting comments. + template Template to use when formatting comments. Overrides + style if specified. In addition to the usual Mercurial + keywords, the extension specifies: + {bug} The Bugzilla bug ID. + {root} The full pathname of the Mercurial repository. + {webroot} Stripped pathname of the Mercurial repository. + {hgweb} Base URL for browsing Mercurial repositories. + Default 'changeset {node|short} in repo {root} refers ' + 'to bug {bug}.\\ndetails:\\n\\t{desc|tabindent}' + strip The number of slashes to strip from the front of {root} + to produce {webroot}. Default 0. + usermap Path of file containing Mercurial committer ID to Bugzilla user + ID mappings. If specified, the file should contain one mapping + per line, "committer"="Bugzilla user". See also the + [usermap] section. + + [usermap] + Any entries in this section specify mappings of Mercurial committer ID + to Bugzilla user ID. See also [bugzilla].usermap. + "committer"="Bugzilla user" + + [web] + baseurl Base URL for browsing Mercurial repositories. Reference from + templates as {hgweb}. + +Activating the extension: + + [extensions] + hgext.bugzilla = + + [hooks] + # run bugzilla hook on every change pulled or pushed in here + incoming.bugzilla = python:hgext.bugzilla.hook + +Example configuration: + +This example configuration is for a collection of Mercurial repositories +in /var/local/hg/repos/ used with a local Bugzilla 3.2 installation in +/opt/bugzilla-3.2. + + [bugzilla] + host=localhost + password=XYZZY + version=3.0 + bzuser=unknown@domain.com + bzdir=/opt/bugzilla-3.2 + template=Changeset {node|short} in {root|basename}.\\n{hgweb}/{webroot}/rev/{node|short}\\n\\n{desc}\\n + strip=5 + + [web] + baseurl=http://dev.domain.com/hg + + [usermap] + user@emaildomain.com=user.name@bugzilladomain.com + +Commits add a comment to the Bugzilla bug record of the form: + + Changeset 3b16791d6642 in repository-name. + http://dev.domain.com/hg/repository-name/rev/3b16791d6642 + + Changeset commit comment. Bug 1234. +''' from mercurial.i18n import _ from mercurial.node import short @@ -82,6 +140,7 @@ self.cursor = self.conn.cursor() self.longdesc_id = self.get_longdesc_id() self.user_ids = {} + self.default_notify = "cd %(bzdir)s && ./processmail %(id)s %(user)s" def run(self, *args, **kwargs): '''run a query.''' @@ -118,15 +177,23 @@ unknown.pop(id, None) return util.sort(unknown.keys()) - def notify(self, ids): + def notify(self, ids, committer): '''tell bugzilla to send mail.''' self.ui.status(_('telling bugzilla to send mail:\n')) + (user, userid) = self.get_bugzilla_user(committer) for id in ids: self.ui.status(_(' bug %s\n') % id) - cmd = self.ui.config('bugzilla', 'notify', - 'cd /var/www/html/bugzilla && ' - './processmail %s nobody@nowhere.com') % id + cmdfmt = self.ui.config('bugzilla', 'notify', self.default_notify) + bzdir = self.ui.config('bugzilla', 'bzdir', '/var/www/html/bugzilla') + try: + # Backwards-compatible with old notify string, which + # took one string. This will throw with a new format + # string. + cmd = cmdfmt % id + except TypeError: + cmd = cmdfmt % {'bzdir': bzdir, 'id': id, 'user': user} + self.ui.note(_('running notify command %s\n') % cmd) fp = util.popen('(%s) 2>&1' % cmd) out = fp.read() ret = fp.close() @@ -161,9 +228,10 @@ return bzuser return user - def add_comment(self, bugid, text, committer): - '''add comment to bug. try adding comment as committer of - changeset, otherwise as default bugzilla user.''' + def get_bugzilla_user(self, committer): + '''see if committer is a registered bugzilla user. Return + bugzilla username and userid if so. If not, return default + bugzilla username and userid.''' user = self.map_committer(committer) try: userid = self.get_user_id(user) @@ -174,9 +242,16 @@ raise util.Abort(_('cannot find bugzilla user id for %s') % user) userid = self.get_user_id(defaultuser) + user = defaultuser except KeyError: raise util.Abort(_('cannot find bugzilla user id for %s or %s') % (user, defaultuser)) + return (user, userid) + + def add_comment(self, bugid, text, committer): + '''add comment to bug. try adding comment as committer of + changeset, otherwise as default bugzilla user.''' + (user, userid) = self.get_bugzilla_user(committer) now = time.strftime('%Y-%m-%d %H:%M:%S') self.run('''insert into longdescs (bug_id, who, bug_when, thetext) @@ -185,12 +260,20 @@ self.run('''insert into bugs_activity (bug_id, who, bug_when, fieldid) values (%s, %s, %s, %s)''', (bugid, userid, now, self.longdesc_id)) + self.conn.commit() -class bugzilla_3_0(bugzilla_2_16): +class bugzilla_2_18(bugzilla_2_16): + '''support for bugzilla 2.18 series.''' + + def __init__(self, ui): + bugzilla_2_16.__init__(self, ui) + self.default_notify = "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s" + +class bugzilla_3_0(bugzilla_2_18): '''support for bugzilla 3.0 series.''' def __init__(self, ui): - bugzilla_2_16.__init__(self, ui) + bugzilla_2_18.__init__(self, ui) def get_longdesc_id(self): '''get identity of longdesc field''' @@ -205,6 +288,7 @@ # different schemas. _versions = { '2.16': bugzilla_2_16, + '2.18': bugzilla_2_18, '3.0': bugzilla_3_0 } @@ -283,7 +367,7 @@ mapfile = self.ui.config('bugzilla', 'style') tmpl = self.ui.config('bugzilla', 'template') t = cmdutil.changeset_templater(self.ui, self.repo, - False, mapfile, False) + False, None, mapfile, False) if not mapfile and not tmpl: tmpl = _('changeset {node|short} in repo {root} refers ' 'to bug {bug}.\ndetails:\n\t{desc|tabindent}') @@ -320,7 +404,7 @@ if ids: for id in ids: bz.update(id, ctx) - bz.notify(ids) + bz.notify(ids, util.email(ctx.user())) except MySQLdb.MySQLError, err: raise util.Abort(_('database error: %s') % err[1]) diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/churn.py --- a/hgext/churn.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/churn.py Fri Feb 27 08:13:42 2009 -0600 @@ -12,31 +12,10 @@ import os, sys import time, datetime -def get_tty_width(): - if 'COLUMNS' in os.environ: - try: - return int(os.environ['COLUMNS']) - except ValueError: - pass - try: - import termios, array, fcntl - for dev in (sys.stdout, sys.stdin): - try: - fd = dev.fileno() - if not os.isatty(fd): - continue - arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8) - return array.array('h', arri)[1] - except ValueError: - pass - except ImportError: - pass - return 80 - def maketemplater(ui, repo, tmpl): tmpl = templater.parsestring(tmpl, quoted=False) try: - t = cmdutil.changeset_templater(ui, repo, False, None, False) + t = cmdutil.changeset_templater(ui, repo, False, None, None, False) except SyntaxError, inst: raise util.Abort(inst.args[0]) t.use_template(tmpl) @@ -100,7 +79,7 @@ newpct = int(100.0 * count / max(len(repo), 1)) if pct < newpct: pct = newpct - ui.write(_("\rGenerating stats: %d%%") % pct) + ui.write(_("\rgenerating stats: %d%%") % pct) sys.stdout.flush() if opts.get('progress'): @@ -111,7 +90,7 @@ def churn(ui, repo, *pats, **opts): - '''Graph count of revisions grouped by template + '''graph count of revisions grouped by template Will graph count of changed lines or revisions grouped by template or alternatively by date, if dateformat is used. In this case it will override @@ -157,7 +136,7 @@ maxcount = float(max([v for k, v in rate])) maxname = max([len(k) for k, v in rate]) - ttywidth = get_tty_width() + ttywidth = util.termwidth() ui.debug(_("assuming %i character terminal\n") % ttywidth) width = ttywidth - maxname - 2 - 6 - 2 - 2 diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/color.py --- a/hgext/color.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/color.py Fri Feb 27 08:13:42 2009 -0600 @@ -204,6 +204,7 @@ _diff_prefixes = [('diff', 'diffline'), ('copy', 'extended'), ('rename', 'extended'), + ('old', 'extended'), ('new', 'extended'), ('deleted', 'extended'), ('---', 'file_a'), diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/convert/__init__.py --- a/hgext/convert/__init__.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/convert/__init__.py Fri Feb 27 08:13:42 2009 -0600 @@ -7,13 +7,14 @@ '''converting foreign VCS repositories to Mercurial''' import convcmd +import cvsps from mercurial import commands from mercurial.i18n import _ # Commands definition was moved elsewhere to ease demandload job. def convert(ui, src, dest=None, revmapfile=None, **opts): - """Convert a foreign SCM repository to a Mercurial one. + """convert a foreign SCM repository to a Mercurial one. Accepted source formats [identifiers]: - Mercurial [hg] @@ -183,7 +184,18 @@ def debugsvnlog(ui, **opts): return convcmd.debugsvnlog(ui, **opts) -commands.norepo += " convert debugsvnlog" +def debugcvsps(ui, *args, **opts): + '''create changeset information from CVS + + This command is intended as a debugging tool for the CVS to Mercurial + converter, and can be used as a direct replacement for cvsps. + + Hg debugcvsps reads the CVS rlog for current directory (or any named + directory) in the CVS repository, and converts the log to a series of + changesets based on matching commit log entries and dates.''' + return cvsps.debugcvsps(ui, *args, **opts) + +commands.norepo += " convert debugsvnlog debugcvsps" cmdtable = { "convert": @@ -200,4 +212,22 @@ (debugsvnlog, [], 'hg debugsvnlog'), + "debugcvsps": + (debugcvsps, + [ + # Main options shared with cvsps-2.1 + ('b', 'branches', [], _('only return changes on specified branches')), + ('p', 'prefix', '', _('prefix to remove from file names')), + ('r', 'revisions', [], _('only return changes after or between specified tags')), + ('u', 'update-cache', None, _("update cvs log cache")), + ('x', 'new-cache', None, _("create new cvs log cache")), + ('z', 'fuzz', 60, _('set commit time fuzz in seconds')), + ('', 'root', '', _('specify cvsroot')), + # Options specific to builtin cvsps + ('', 'parents', '', _('show parent changesets')), + ('', 'ancestors', '', _('show current changeset in ancestor branches')), + # Options that are ignored for compatibility with cvsps-2.1 + ('A', 'cvs-direct', None, _('ignored for compatibility')), + ], + _('hg debugcvsps [OPTION]... [PATH]...')), } diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/convert/common.py --- a/hgext/convert/common.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/convert/common.py Fri Feb 27 08:13:42 2009 -0600 @@ -228,7 +228,9 @@ except TypeError: pass cmdline = [util.shellquote(arg) for arg in cmdline] - cmdline += ['2>', util.nulldev, '<', util.nulldev] + if not self.ui.debugflag: + cmdline += ['2>', util.nulldev] + cmdline += ['<', util.nulldev] cmdline = ' '.join(cmdline) return cmdline @@ -323,7 +325,7 @@ self._read() def _read(self): - if self.path is None: + if not self.path: return try: fp = open(self.path, 'r') diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/convert/convcmd.py --- a/hgext/convert/convcmd.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/convert/convcmd.py Fri Feb 27 08:13:42 2009 -0600 @@ -206,7 +206,7 @@ _('Overriding mapping for author %s, was %s, will be %s\n') % (srcauthor, self.authors[srcauthor], dstauthor)) else: - self.ui.debug(_('Mapping author %s to %s\n') + self.ui.debug(_('mapping author %s to %s\n') % (srcauthor, dstauthor)) self.authors[srcauthor] = dstauthor except IndexError: diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/convert/cvs.py --- a/hgext/convert/cvs.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/convert/cvs.py Fri Feb 27 08:13:42 2009 -0600 @@ -144,11 +144,11 @@ if branch == "HEAD": branch = "" if branch: - latest = None + latest = 0 # the last changeset that contains a base # file is our parent for r in oldrevs: - latest = max(filerevids.get(r, None), latest) + latest = max(filerevids.get(r, 0), latest) if latest: p = [latest] diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/convert/cvsps --- a/hgext/convert/cvsps Sun Jan 25 19:15:49 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -#!/usr/bin/env python -# -# Commandline front-end for cvsps.py -# -# Copyright 2008, Frank Kingswood -# -# This software may be used and distributed according to the terms -# of the GNU General Public License, incorporated herein by reference. - -import sys -from mercurial import util -from mercurial.i18n import _ -from optparse import OptionParser, SUPPRESS_HELP -from hgext.convert.cvsps import createlog, createchangeset, logerror - -def main(): - '''Main program to mimic cvsps.''' - - op = OptionParser(usage='%prog [-bpruvxz] path', - description='Read CVS rlog for current directory or named ' - 'path in repository, and convert the log to changesets ' - 'based on matching commit log entries and dates.') - - # Options that are ignored for compatibility with cvsps-2.1 - op.add_option('-A', dest='Ignore', action='store_true', help=SUPPRESS_HELP) - op.add_option('--cvs-direct', dest='Ignore', action='store_true', help=SUPPRESS_HELP) - op.add_option('-q', dest='Ignore', action='store_true', help=SUPPRESS_HELP) - - # Main options shared with cvsps-2.1 - op.add_option('-b', dest='Branches', action='append', default=[], - help='Only return changes on specified branches') - op.add_option('-p', dest='Prefix', action='store', default='', - help='Prefix to remove from file names') - op.add_option('-r', dest='Revisions', action='append', default=[], - help='Only return changes after or between specified tags') - op.add_option('-u', dest='Cache', action='store_const', const='update', - help="Update cvs log cache") - op.add_option('-v', dest='Verbose', action='count', default=0, - help='Be verbose') - op.add_option('-x', dest='Cache', action='store_const', const='write', - help="Create new cvs log cache") - op.add_option('-z', dest='Fuzz', action='store', type='int', default=60, - help='Set commit time fuzz', metavar='seconds') - op.add_option('--root', dest='Root', action='store', default='', - help='Specify cvsroot', metavar='cvsroot') - - # Options specific to this version - op.add_option('--parents', dest='Parents', action='store_true', - help='Show parent changesets') - op.add_option('--ancestors', dest='Ancestors', action='store_true', - help='Show current changeset in ancestor branches') - - options, args = op.parse_args() - - # Create a ui object for printing progress messages - class UI: - def __init__(self, verbose): - if verbose: - self.status = self.message - if verbose>1: - self.note = self.message - if verbose>2: - self.debug = self.message - def message(self, msg): - sys.stderr.write(msg) - def nomessage(self, msg): - pass - status = nomessage - note = nomessage - debug = nomessage - ui = UI(options.Verbose) - - try: - if args: - log = [] - for d in args: - log += createlog(ui, d, root=options.Root, cache=options.Cache) - else: - log = createlog(ui, root=options.Root, cache=options.Cache) - except logerror, e: - print e - return - - changesets = createchangeset(ui, log, options.Fuzz) - del log - - # Print changesets (optionally filtered) - - off = len(options.Revisions) - branches = {} # latest version number in each branch - ancestors = {} # parent branch - for cs in changesets: - - if options.Ancestors: - if cs.branch not in branches and cs.parents and cs.parents[0].id: - ancestors[cs.branch] = changesets[cs.parents[0].id-1].branch, cs.parents[0].id - branches[cs.branch] = cs.id - - # limit by branches - if options.Branches and (cs.branch or 'HEAD') not in options.Branches: - continue - - if not off: - # Note: trailing spaces on several lines here are needed to have - # bug-for-bug compatibility with cvsps. - print '---------------------' - print 'PatchSet %d ' % cs.id - print 'Date: %s' % util.datestr(cs.date, '%Y/%m/%d %H:%M:%S %1%2') - print 'Author: %s' % cs.author - print 'Branch: %s' % (cs.branch or 'HEAD') - print 'Tag%s: %s ' % (['', 's'][len(cs.tags)>1], - ','.join(cs.tags) or '(none)') - if options.Parents and cs.parents: - if len(cs.parents)>1: - print 'Parents: %s' % (','.join([str(p.id) for p in cs.parents])) - else: - print 'Parent: %d' % cs.parents[0].id - - if options.Ancestors: - b = cs.branch - r = [] - while b: - b, c = ancestors[b] - r.append('%s:%d:%d' % (b or "HEAD", c, branches[b])) - if r: - print 'Ancestors: %s' % (','.join(r)) - - print 'Log:' - print cs.comment - print - print 'Members: ' - for f in cs.entries: - fn = f.file - if fn.startswith(options.Prefix): - fn = fn[len(options.Prefix):] - print '\t%s:%s->%s%s ' % (fn, '.'.join([str(x) for x in f.parent]) or 'INITIAL', - '.'.join([str(x) for x in f.revision]), ['', '(DEAD)'][f.dead]) - print - - # have we seen the start tag? - if options.Revisions and off: - if options.Revisions[0] == str(cs.id) or \ - options.Revisions[0] in cs.tags: - off = False - - # see if we reached the end tag - if len(options.Revisions)>1 and not off: - if options.Revisions[1] == str(cs.id) or \ - options.Revisions[1] in cs.tags: - break - - -if __name__ == '__main__': - main() diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/convert/cvsps.py --- a/hgext/convert/cvsps.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/convert/cvsps.py Fri Feb 27 08:13:42 2009 -0600 @@ -191,7 +191,13 @@ ui.note(_("running %s\n") % (' '.join(cmd))) ui.debug(_("prefix=%r directory=%r root=%r\n") % (prefix, directory, root)) - for line in util.popen(' '.join(cmd)): + pfp = util.popen(' '.join(cmd)) + peek = pfp.readline() + while True: + line = peek + if line == '': + break + peek = pfp.readline() if line.endswith('\n'): line = line[:-1] #ui.debug('state=%d line=%r\n' % (state, line)) @@ -263,7 +269,7 @@ if re_31.match(line): state = 5 else: - assert not re_32.match(line), _('Must have at least some revisions') + assert not re_32.match(line), _('must have at least some revisions') elif state == 5: # expecting revision number and possibly (ignored) lock indication @@ -312,7 +318,7 @@ e.branches = [tuple([int(y) for y in x.strip().split('.')]) for x in m.group(1).split(';')] state = 8 - elif re_31.match(line): + elif re_31.match(line) and re_50.match(peek): state = 5 store = True elif re_32.match(line): @@ -584,3 +590,95 @@ ui.status(_('%d changeset entries\n') % len(changesets)) return changesets + + +def debugcvsps(ui, *args, **opts): + '''Read CVS rlog for current directory or named path in repository, and + convert the log to changesets based on matching commit log entries and dates.''' + + if opts["new_cache"]: + cache = "write" + elif opts["update_cache"]: + cache = "update" + else: + cache = None + + revisions = opts["revisions"] + + try: + if args: + log = [] + for d in args: + log += createlog(ui, d, root=opts["root"], cache=cache) + else: + log = createlog(ui, root=opts["root"], cache=cache) + except logerror, e: + ui.write("%r\n"%e) + return + + changesets = createchangeset(ui, log, opts["fuzz"]) + del log + + # Print changesets (optionally filtered) + + off = len(revisions) + branches = {} # latest version number in each branch + ancestors = {} # parent branch + for cs in changesets: + + if opts["ancestors"]: + if cs.branch not in branches and cs.parents and cs.parents[0].id: + ancestors[cs.branch] = changesets[cs.parents[0].id-1].branch, cs.parents[0].id + branches[cs.branch] = cs.id + + # limit by branches + if opts["branches"] and (cs.branch or 'HEAD') not in opts["branches"]: + continue + + if not off: + # Note: trailing spaces on several lines here are needed to have + # bug-for-bug compatibility with cvsps. + ui.write('---------------------\n') + ui.write('PatchSet %d \n' % cs.id) + ui.write('Date: %s\n' % util.datestr(cs.date, '%Y/%m/%d %H:%M:%S %1%2')) + ui.write('Author: %s\n' % cs.author) + ui.write('Branch: %s\n' % (cs.branch or 'HEAD')) + ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags)>1], + ','.join(cs.tags) or '(none)')) + if opts["parents"] and cs.parents: + if len(cs.parents)>1: + ui.write('Parents: %s\n' % (','.join([str(p.id) for p in cs.parents]))) + else: + ui.write('Parent: %d\n' % cs.parents[0].id) + + if opts["ancestors"]: + b = cs.branch + r = [] + while b: + b, c = ancestors[b] + r.append('%s:%d:%d' % (b or "HEAD", c, branches[b])) + if r: + ui.write('Ancestors: %s\n' % (','.join(r))) + + ui.write('Log:\n') + ui.write('%s\n\n' % cs.comment) + ui.write('Members: \n') + for f in cs.entries: + fn = f.file + if fn.startswith(opts["prefix"]): + fn = fn[len(opts["prefix"]):] + ui.write('\t%s:%s->%s%s \n' % (fn, '.'.join([str(x) for x in f.parent]) or 'INITIAL', + '.'.join([str(x) for x in f.revision]), ['', '(DEAD)'][f.dead])) + ui.write('\n') + + # have we seen the start tag? + if revisions and off: + if revisions[0] == str(cs.id) or \ + revisions[0] in cs.tags: + off = False + + # see if we reached the end tag + if len(revisions)>1 and not off: + if revisions[1] == str(cs.id) or \ + revisions[1] in cs.tags: + break diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/convert/darcs.py --- a/hgext/convert/darcs.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/convert/darcs.py Fri Feb 27 08:13:42 2009 -0600 @@ -32,7 +32,7 @@ if ElementTree is None: raise util.Abort(_("Python ElementTree module is not available")) - if not os.path.exists(os.path.join(path, '_darcs', 'inventory')): + if not os.path.exists(os.path.join(path, '_darcs', 'inventories')): raise NoRepo("%s does not look like a darcs repo" % path) self.path = os.path.realpath(path) diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/convert/gnuarch.py --- a/hgext/convert/gnuarch.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/convert/gnuarch.py Fri Feb 27 08:13:42 2009 -0600 @@ -3,7 +3,8 @@ from common import NoRepo, commandline, commit, converter_source from mercurial.i18n import _ from mercurial import util -import os, shutil, tempfile, stat +import os, shutil, tempfile, stat, locale +from email.Parser import Parser class gnuarch_source(converter_source, commandline): @@ -13,6 +14,7 @@ self.summary = '' self.date = None self.author = '' + self.continuationof = None self.add_files = [] self.mod_files = [] self.del_files = [] @@ -46,38 +48,74 @@ self.parents = {} self.tags = {} self.modecache = {} + self.catlogparser = Parser() + self.locale = locale.getpreferredencoding() + self.archives = [] def before(self): + # Get registered archives + self.archives = [i.rstrip('\n') + for i in self.runlines0('archives', '-n')] + if self.execmd == 'tla': output = self.run0('tree-version', self.path) else: output = self.run0('tree-version', '-d', self.path) self.treeversion = output.strip() - self.ui.status(_('analyzing tree version %s...\n') % self.treeversion) - # Get name of temporary directory version = self.treeversion.split('/') self.tmppath = os.path.join(tempfile.gettempdir(), 'hg-%s' % version[1]) # Generate parents dictionary - child = [] - output, status = self.runlines('revisions', self.treeversion) - self.checkexit(status, 'archive registered?') - for l in output: - rev = l.strip() - self.changes[rev] = self.gnuarch_rev(rev) + self.parents[None] = [] + treeversion = self.treeversion + child = None + while treeversion: + self.ui.status(_('analyzing tree version %s...\n') % treeversion) + + archive = treeversion.split('/')[0] + if archive not in self.archives: + self.ui.status(_('tree analysis stopped because it points to an unregistered archive %s...\n') % archive) + break + + # Get the complete list of revisions for that tree version + output, status = self.runlines('revisions', '-r', '-f', treeversion) + self.checkexit(status, 'failed retrieveing revisions for %s' % treeversion) + + # No new iteration unless a revision has a continuation-of header + treeversion = None + + for l in output: + rev = l.strip() + self.changes[rev] = self.gnuarch_rev(rev) + self.parents[rev] = [] - # Read author, date and summary - catlog = self.runlines0('cat-log', '-d', self.path, rev) - self._parsecatlog(catlog, rev) + # Read author, date and summary + catlog, status = self.run('cat-log', '-d', self.path, rev) + if status: + catlog = self.run0('cat-archive-log', rev) + self._parsecatlog(catlog, rev) + + # Populate the parents map + self.parents[child].append(rev) - self.parents[rev] = child - child = [rev] - if rev == self.rev: - break - self.parents[None] = child + # Keep track of the current revision as the child of the next + # revision scanned + child = rev + + # Check if we have to follow the usual incremental history + # or if we have to 'jump' to a different treeversion given + # by the continuation-of header. + if self.changes[rev].continuationof: + treeversion = '--'.join(self.changes[rev].continuationof.split('--')[:-1]) + break + + # If we reached a base-0 revision w/o any continuation-of + # header, it means the tree history ends here. + if rev[-6:] == 'base-0': + break def after(self): self.ui.debug(_('cleaning up %s\n') % self.tmppath) @@ -135,7 +173,7 @@ def getcommit(self, rev): changes = self.changes[rev] return commit(author = changes.author, date = changes.date, - desc = changes.summary, parents = self.parents[rev]) + desc = changes.summary, parents = self.parents[rev], rev=rev) def gettags(self): return self.tags @@ -150,26 +188,19 @@ return os.system(cmdline) def _update(self, rev): - if rev == 'base-0': - # Initialise 'base-0' revision + self.ui.debug(_('applying revision %s...\n') % rev) + changeset, status = self.runlines('replay', '-d', self.tmppath, + rev) + if status: + # Something went wrong while merging (baz or tla + # issue?), get latest revision and try from there + shutil.rmtree(self.tmppath, ignore_errors=True) self._obtainrevision(rev) else: - self.ui.debug(_('applying revision %s...\n') % rev) - revision = '%s--%s' % (self.treeversion, rev) - changeset, status = self.runlines('replay', '-d', self.tmppath, - revision) - if status: - # Something went wrong while merging (baz or tla - # issue?), get latest revision and try from there - shutil.rmtree(self.tmppath, ignore_errors=True) - self._obtainrevision(rev) - else: - old_rev = self.parents[rev][0] - self.ui.debug(_('computing changeset between %s and %s...\n') - % (old_rev, rev)) - rev_a = '%s--%s' % (self.treeversion, old_rev) - rev_b = '%s--%s' % (self.treeversion, rev) - self._parsechangeset(changeset, rev) + old_rev = self.parents[rev][0] + self.ui.debug(_('computing changeset between %s and %s...\n') + % (old_rev, rev)) + self._parsechangeset(changeset, rev) def _getfile(self, name, rev): mode = os.lstat(os.path.join(self.tmppath, name)).st_mode @@ -217,8 +248,7 @@ def _obtainrevision(self, rev): self.ui.debug(_('obtaining revision %s...\n') % rev) - revision = '%s--%s' % (self.treeversion, rev) - output = self._execute('get', revision, self.tmppath) + output = self._execute('get', rev, self.tmppath) self.checkexit(output) self.ui.debug(_('analysing revision %s...\n') % rev) files = self._readcontents(self.tmppath) @@ -230,20 +260,27 @@ return path def _parsecatlog(self, data, rev): - summary = [] - for l in data: - l = l.strip() - if summary: - summary.append(l) - elif l.startswith('Summary:'): - summary.append(l[len('Summary: '):]) - elif l.startswith('Standard-date:'): - date = l[len('Standard-date: '):] - strdate = util.strdate(date, '%Y-%m-%d %H:%M:%S') - self.changes[rev].date = util.datestr(strdate) - elif l.startswith('Creator:'): - self.changes[rev].author = l[len('Creator: '):] - self.changes[rev].summary = '\n'.join(summary) + try: + catlog = self.catlogparser.parsestr(data) + + # Commit date + self.changes[rev].date = util.datestr( + util.strdate(catlog['Standard-date'], + '%Y-%m-%d %H:%M:%S')) + + # Commit author + self.changes[rev].author = self.recode(catlog['Creator']) + + # Commit description + self.changes[rev].summary = '\n\n'.join((catlog['Summary'], + catlog.get_payload())) + self.changes[rev].summary = self.recode(self.changes[rev].summary) + + # Commit revision origin when dealing with a branch or tag + if catlog.has_key('Continuation-of'): + self.changes[rev].continuationof = self.recode(catlog['Continuation-of']) + except Exception, err: + raise util.Abort(_('could not parse cat-log of %s') % rev) def _parsechangeset(self, data, rev): for l in data: diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/convert/hg.py --- a/hgext/convert/hg.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/convert/hg.py Fri Feb 27 08:13:42 2009 -0600 @@ -15,9 +15,8 @@ import os, time from mercurial.i18n import _ -from mercurial.repo import RepoError from mercurial.node import bin, hex, nullid -from mercurial import hg, revlog, util, context +from mercurial import hg, util, context, error from common import NoRepo, commit, converter_source, converter_sink @@ -33,7 +32,7 @@ self.repo = hg.repository(self.ui, path) if not self.repo.local(): raise NoRepo(_('%s is not a local Mercurial repo') % path) - except RepoError, err: + except error.RepoError, err: ui.print_exc() raise NoRepo(err.args[0]) else: @@ -43,7 +42,7 @@ if not self.repo.local(): raise NoRepo(_('%s is not a local Mercurial repo') % path) self.created.append(path) - except RepoError, err: + except error.RepoError, err: ui.print_exc() raise NoRepo("could not create hg repo %s as sink" % path) self.lock = None @@ -159,7 +158,7 @@ try: parentctx = self.repo[self.tagsbranch] tagparent = parentctx.node() - except RepoError, inst: + except error.RepoError, inst: parentctx = None tagparent = nullid @@ -200,8 +199,8 @@ # try to provoke an exception if this isn't really a hg # repo, but some other bogus compatible-looking url if not self.repo.local(): - raise RepoError() - except RepoError: + raise error.RepoError() + except error.RepoError: ui.print_exc() raise NoRepo("%s is not a local Mercurial repo" % path) self.lastrev = None @@ -213,7 +212,7 @@ if startnode is not None: try: startnode = self.repo.lookup(startnode) - except repo.RepoError: + except error.RepoError: raise util.Abort(_('%s is not a valid start revision') % startnode) startrev = self.repo.changelog.rev(startnode) @@ -244,7 +243,7 @@ def getfile(self, name, rev): try: return self.changectx(rev)[name].data() - except revlog.LookupError, err: + except error.LookupError, err: raise IOError(err) def getmode(self, name, rev): @@ -283,7 +282,7 @@ copies[name] = copysource except TypeError: pass - except revlog.LookupError, e: + except error.LookupError, e: if not self.ignoreerrors: raise self.ignored[name] = 1 diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/convert/subversion.py --- a/hgext/convert/subversion.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/convert/subversion.py Fri Feb 27 08:13:42 2009 -0600 @@ -601,7 +601,7 @@ part = "/".join(parts[:i]) info = part, copyfrom.get(part, None) if info[1] is not None: - self.ui.debug(_("Found parent directory %s\n") % info[1]) + self.ui.debug(_("found parent directory %s\n") % info[1]) rc = info return rc @@ -616,7 +616,7 @@ self.ui.debug(entrypath[len(frompath):] + '\n') entrypath = froment.copyfrom_path + entrypath[len(frompath):] fromrev = froment.copyfrom_rev - self.ui.debug(_("Info: %s %s %s %s\n") % (frompath, froment, ent, entrypath)) + self.ui.debug(_("info: %s %s %s %s\n") % (frompath, froment, ent, entrypath)) # We can avoid the reparent calls if the module has not changed # but it probably does not worth the pain. @@ -757,7 +757,7 @@ self.ui.note(_('found parent of branch %s at %d: %s\n') % (self.module, prevnum, prevmodule)) else: - self.ui.debug(_("No copyfrom path, don't know what to do.\n")) + self.ui.debug(_("no copyfrom path, don't know what to do.\n")) paths = [] # filter out unrelated paths diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/extdiff.py --- a/hgext/extdiff.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/extdiff.py Fri Feb 27 08:13:42 2009 -0600 @@ -80,9 +80,7 @@ '''snapshot files from working directory. if not using snapshot, -I/-X does not work and recursive diff in tools like kdiff3 and meld displays too many files.''' - repo_root = repo.root - - dirname = os.path.basename(repo_root) + dirname = os.path.basename(repo.root) if dirname == "": dirname = "root" base = os.path.join(tmproot, dirname) @@ -105,8 +103,7 @@ fp.write(chunk) fp.close() - fns_and_mtime.append((dest, os.path.join(repo_root, fn), - os.path.getmtime(dest))) + fns_and_mtime.append((dest, repo.wjoin(fn), os.path.getmtime(dest))) return dirname, fns_and_mtime @@ -120,7 +117,19 @@ another one and more than 1 file is changed - just invoke the diff for a single file in the working dir ''' - node1, node2 = cmdutil.revpair(repo, opts['rev']) + + revs = opts.get('rev') + change = opts.get('change') + + if revs and change: + msg = _('cannot specify --rev and --change at the same time') + raise util.Abort(msg) + elif change: + node2 = repo.lookup(change) + node1 = repo[node2].parents()[0].node() + else: + node1, node2 = cmdutil.revpair(repo, revs) + matcher = cmdutil.match(repo, pats, opts) modified, added, removed = repo.status(node1, node2, matcher)[:3] if not (modified or added or removed): @@ -169,7 +178,7 @@ for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: - ui.debug(_('File changed while diffing. ' + ui.debug(_('file changed while diffing. ' 'Overwriting: %s (src: %s)\n') % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn) @@ -208,6 +217,7 @@ [('p', 'program', '', _('comparison program to run')), ('o', 'option', [], _('pass option to comparison program')), ('r', 'rev', [], _('revision')), + ('c', 'change', '', _('change made by revision')), ] + commands.walkopts, _('hg extdiff [OPT]... [FILE]...')), } diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/fetch.py --- a/hgext/fetch.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/fetch.py Fri Feb 27 08:13:42 2009 -0600 @@ -11,7 +11,7 @@ from mercurial import commands, cmdutil, hg, util, url def fetch(ui, repo, source='default', **opts): - '''Pull changes from a remote repository, merge new changes if needed. + '''pull changes from a remote repository, merge new changes if needed. This finds all changes from the repository at the specified path or URL and adds them to the local repository. diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/graphlog.py --- a/hgext/graphlog.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/graphlog.py Fri Feb 27 08:13:42 2009 -0600 @@ -17,9 +17,8 @@ from mercurial.commands import templateopts, logopts, remoteopts from mercurial.i18n import _ from mercurial.node import nullrev -from mercurial.util import Abort, canonpath from mercurial import bundlerepo, changegroup, cmdutil, commands, extensions -from mercurial import hg, ui, url +from mercurial import hg, ui, url, util def revisions(repo, start, stop): """cset DAG generator yielding (rev, node, [parents]) tuples @@ -245,18 +244,6 @@ prev_node_index = node_index prev_n_columns_diff = n_columns_diff -def get_limit(limit_opt): - if limit_opt: - try: - limit = int(limit_opt) - except ValueError: - raise Abort(_("limit must be a positive integer")) - if limit <= 0: - raise Abort(_("limit must be positive")) - else: - limit = sys.maxint - return limit - def get_revs(repo, rev_opt): if rev_opt: revs = revrange(repo, rev_opt) @@ -269,8 +256,7 @@ "only_merges", "user", "only_branch", "prune", "newest_first", "no_merges", "include", "exclude"]: if op in opts and opts[op]: - raise Abort(_("--graph option is incompatible with --%s") % op) - + raise util.Abort(_("--graph option is incompatible with --%s") % op) def graphlog(ui, repo, path=None, **opts): """show revision history alongside an ASCII revision graph @@ -283,39 +269,56 @@ """ check_unsupported_flags(opts) - limit = get_limit(opts["limit"]) + limit = cmdutil.loglimit(opts) start, stop = get_revs(repo, opts["rev"]) stop = max(stop, start - limit + 1) if start == nullrev: return if path: - path = canonpath(repo.root, os.getcwd(), path) + path = util.canonpath(repo.root, os.getcwd(), path) if path: # could be reset in canonpath revdag = filerevs(repo, path, start, stop) else: revdag = revisions(repo, start, stop) - repo_parents = repo.dirstate.parents() + graphdag = graphabledag(ui, repo, revdag, opts) + ascii(ui, grapher(graphdag)) + +def graphrevs(repo, nodes, opts): + nodes.reverse() + include = util.set(nodes) + limit = cmdutil.loglimit(opts) + count = 0 + for node in nodes: + if count >= limit: + break + ctx = repo[node] + parents = [p.rev() for p in ctx.parents() if p.node() in include] + parents.sort() + yield (ctx, parents) + count += 1 + +def graphabledag(ui, repo, revdag, opts): + showparents = [ctx.node() for ctx in repo[None].parents()] displayer = show_changeset(ui, repo, opts, buffered=True) - def graphabledag(): - for (ctx, parents) in revdag: - # log_strings is the list of all log strings to draw alongside - # the graph. - displayer.show(ctx) - lines = displayer.hunk.pop(ctx.rev()).split("\n")[:-1] - char = ctx.node() in repo_parents and '@' or 'o' - yield (ctx.rev(), parents, char, lines) + for (ctx, parents) in revdag: + displayer.show(ctx) + lines = displayer.hunk.pop(ctx.rev()).split('\n')[:-1] + char = ctx.node() in showparents and '@' or 'o' + yield (ctx.rev(), parents, char, lines) + +def goutgoing(ui, repo, dest=None, **opts): + """show the outgoing changesets alongside an ASCII revision graph - ascii(ui, grapher(graphabledag())) - -def outgoing_revs(ui, repo, dest, opts): - """cset DAG generator yielding (node, [parents]) tuples + Print the outgoing changesets alongside a revision graph drawn with + ASCII characters. - This generator function walks through the revisions not found - in the destination + Nodes printed as an @ character are parents of the working + directory. """ - limit = cmdutil.loglimit(opts) + + check_unsupported_flags(opts) dest, revs, checkout = hg.parseurl( ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev')) @@ -328,65 +331,11 @@ if not o: ui.status(_("no changes found\n")) return + o = repo.changelog.nodesbetween(o, revs)[0] - o.reverse() - revdict = {} - for n in o: - revdict[repo.changectx(n).rev()]=True - count = 0 - for n in o: - if count >= limit: - break - ctx = repo.changectx(n) - parents = [p.rev() for p in ctx.parents() if p.rev() in revdict] - parents.sort() - yield (ctx, parents) - count += 1 - -def goutgoing(ui, repo, dest=None, **opts): - """show the outgoing changesets alongside an ASCII revision graph - - Print the outgoing changesets alongside a revision graph drawn with - ASCII characters. - - Nodes printed as an @ character are parents of the working - directory. - """ - check_unsupported_flags(opts) - revdag = outgoing_revs(ui, repo, dest, opts) - repo_parents = repo.dirstate.parents() - displayer = show_changeset(ui, repo, opts, buffered=True) - def graphabledag(): - for (ctx, parents) in revdag: - # log_strings is the list of all log strings to draw alongside - # the graph. - displayer.show(ctx) - lines = displayer.hunk.pop(ctx.rev()).split("\n")[:-1] - char = ctx.node() in repo_parents and '@' or 'o' - yield (ctx.rev(), parents, char, lines) - - ascii(ui, grapher(graphabledag())) - -def incoming_revs(other, chlist, opts): - """cset DAG generator yielding (node, [parents]) tuples - - This generator function walks through the revisions of the destination - not found in repo - """ - limit = cmdutil.loglimit(opts) - chlist.reverse() - revdict = {} - for n in chlist: - revdict[other.changectx(n).rev()]=True - count = 0 - for n in chlist: - if count >= limit: - break - ctx = other.changectx(n) - parents = [p.rev() for p in ctx.parents() if p.rev() in revdict] - parents.sort() - yield (ctx, parents) - count += 1 + revdag = graphrevs(repo, o, opts) + graphdag = graphabledag(ui, repo, revdag, opts) + ascii(ui, grapher(graphdag)) def gincoming(ui, repo, source="default", **opts): """show the incoming changesets alongside an ASCII revision graph @@ -417,6 +366,7 @@ cleanup = None try: + fname = opts["bundle"] if fname or not other.local(): # create a bundle (uncompressed if other repo is not local) @@ -434,19 +384,12 @@ other = bundlerepo.bundlerepository(ui, repo.root, fname) chlist = other.changelog.nodesbetween(incoming, revs)[0] - revdag = incoming_revs(other, chlist, opts) + revdag = graphrevs(other, chlist, opts) other_parents = [] displayer = show_changeset(ui, other, opts, buffered=True) - def graphabledag(): - for (ctx, parents) in revdag: - # log_strings is the list of all log strings to draw alongside - # the graph. - displayer.show(ctx) - lines = displayer.hunk.pop(ctx.rev()).split("\n")[:-1] - char = ctx.node() in other_parents and '@' or 'o' - yield (ctx.rev(), parents, char, lines) + graphdag = graphabledag(ui, repo, revdag, opts) + ascii(ui, grapher(graphdag)) - ascii(ui, grapher(graphabledag())) finally: if hasattr(other, 'close'): other.close() @@ -466,7 +409,7 @@ return wrapfn(*args, **kwargs) return orig(*args, **kwargs) entry = extensions.wrapcommand(table, cmd, graph) - entry[1].append(('g', 'graph', None, _("show the revision DAG"))) + entry[1].append(('G', 'graph', None, _("show the revision DAG"))) cmdtable = { "glog": diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/hgcia.py --- a/hgext/hgcia.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/hgcia.py Fri Feb 27 08:13:42 2009 -0600 @@ -188,7 +188,8 @@ if not template: template = self.diffstat and self.dstemplate or self.deftemplate template = templater.parsestring(template, quoted=False) - t = cmdutil.changeset_templater(self.ui, self.repo, False, style, False) + t = cmdutil.changeset_templater(self.ui, self.repo, False, None, + style, False) t.use_template(template) self.templater = t diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/hgk.py --- a/hgext/hgk.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/hgk.py Fri Feb 27 08:13:42 2009 -0600 @@ -130,7 +130,7 @@ ui.write('\0') def base(ui, repo, node1, node2): - """Output common ancestor information""" + """output common ancestor information""" node1 = repo.lookup(node1) node2 = repo.lookup(node2) n = repo.changelog.ancestor(node1, node2) @@ -282,7 +282,7 @@ count += 1 def revparse(ui, repo, *revs, **opts): - """Parse given revisions""" + """parse given revisions""" def revstr(rev): if rev == 'HEAD': rev = 'tip' diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/imerge.py --- a/hgext/imerge.py Sun Jan 25 19:15:49 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,407 +0,0 @@ -# Copyright (C) 2007 Brendan Cully -# Published under the GNU GPL - -''' -imerge - interactive merge -''' - -from mercurial.i18n import _ -from mercurial.node import hex, short -from mercurial import commands, cmdutil, dispatch, fancyopts -from mercurial import hg, filemerge, util, revlog -import os, tarfile - -class InvalidStateFileException(Exception): pass - -class ImergeStateFile(object): - def __init__(self, im): - self.im = im - - def save(self, dest): - tf = tarfile.open(dest, 'w:gz') - - st = os.path.join(self.im.path, 'status') - tf.add(st, os.path.join('.hg', 'imerge', 'status')) - - for f in self.im.resolved: - (fd, fo) = self.im.conflicts[f] - abssrc = self.im.repo.wjoin(fd) - tf.add(abssrc, fd) - - tf.close() - - def load(self, source): - wlock = self.im.repo.wlock() - lock = self.im.repo.lock() - - tf = tarfile.open(source, 'r') - contents = tf.getnames() - # tarfile normalizes path separators to '/' - statusfile = '.hg/imerge/status' - if statusfile not in contents: - raise InvalidStateFileException('no status file') - - tf.extract(statusfile, self.im.repo.root) - p1, p2 = self.im.load() - if self.im.repo.dirstate.parents()[0] != p1.node(): - hg.clean(self.im.repo, p1.node()) - self.im.start(p2.node()) - for tarinfo in tf: - tf.extract(tarinfo, self.im.repo.root) - self.im.load() - -class Imerge(object): - def __init__(self, ui, repo): - self.ui = ui - self.repo = repo - - self.path = repo.join('imerge') - self.opener = util.opener(self.path) - - self.wctx = self.repo.workingctx() - self.conflicts = {} - self.resolved = [] - - def merging(self): - return len(self.wctx.parents()) > 1 - - def load(self): - # status format. \0-delimited file, fields are - # p1, p2, conflict count, conflict filenames, resolved filenames - # conflict filenames are tuples of localname, remoteorig, remotenew - - statusfile = self.opener('status') - - status = statusfile.read().split('\0') - if len(status) < 3: - raise util.Abort(_('invalid imerge status file')) - - try: - parents = [self.repo.changectx(n) for n in status[:2]] - except revlog.LookupError, e: - raise util.Abort(_('merge parent %s not in repository') % - short(e.name)) - - status = status[2:] - conflicts = int(status.pop(0)) * 3 - self.resolved = status[conflicts:] - for i in xrange(0, conflicts, 3): - self.conflicts[status[i]] = (status[i+1], status[i+2]) - - return parents - - def save(self): - lock = self.repo.lock() - - if not os.path.isdir(self.path): - os.mkdir(self.path) - statusfile = self.opener('status', 'wb') - - out = [hex(n.node()) for n in self.wctx.parents()] - out.append(str(len(self.conflicts))) - conflicts = self.conflicts.items() - conflicts.sort() - for fw, fd_fo in conflicts: - out.append(fw) - out.extend(fd_fo) - out.extend(self.resolved) - - statusfile.write('\0'.join(out)) - - def remaining(self): - return [f for f in self.conflicts if f not in self.resolved] - - def filemerge(self, fn, interactive=True): - wlock = self.repo.wlock() - - (fd, fo) = self.conflicts[fn] - p1, p2 = self.wctx.parents() - - # this could be greatly improved - realmerge = os.environ.get('HGMERGE') - if not interactive: - os.environ['HGMERGE'] = 'internal:merge' - - # The filemerge ancestor algorithm does not work if self.wctx - # already has two parents (in normal merge it doesn't yet). But - # this is very dirty. - self.wctx._parents.pop() - try: - # TODO: we should probably revert the file if merge fails - return filemerge.filemerge(self.repo, fn, fd, fo, self.wctx, p2) - finally: - self.wctx._parents.append(p2) - if realmerge: - os.environ['HGMERGE'] = realmerge - elif not interactive: - del os.environ['HGMERGE'] - - def start(self, rev=None): - _filemerge = filemerge.filemerge - def filemerge_(repo, fw, fd, fo, wctx, mctx): - self.conflicts[fw] = (fd, fo) - - filemerge.filemerge = filemerge_ - commands.merge(self.ui, self.repo, rev=rev) - filemerge.filemerge = _filemerge - - self.wctx = self.repo.workingctx() - self.save() - - def resume(self): - self.load() - - dp = self.repo.dirstate.parents() - p1, p2 = self.wctx.parents() - if p1.node() != dp[0] or p2.node() != dp[1]: - raise util.Abort(_('imerge state does not match working directory')) - - def next(self): - remaining = self.remaining() - return remaining and remaining[0] - - def resolve(self, files): - resolved = dict.fromkeys(self.resolved) - for fn in files: - if fn not in self.conflicts: - raise util.Abort(_('%s is not in the merge set') % fn) - resolved[fn] = True - self.resolved = resolved.keys() - self.resolved.sort() - self.save() - return 0 - - def unresolve(self, files): - resolved = dict.fromkeys(self.resolved) - for fn in files: - if fn not in resolved: - raise util.Abort(_('%s is not resolved') % fn) - del resolved[fn] - self.resolved = resolved.keys() - self.resolved.sort() - self.save() - return 0 - - def pickle(self, dest): - '''write current merge state to file to be resumed elsewhere''' - state = ImergeStateFile(self) - return state.save(dest) - - def unpickle(self, source): - '''read merge state from file''' - state = ImergeStateFile(self) - return state.load(source) - -def load(im, source): - if im.merging(): - raise util.Abort(_('there is already a merge in progress ' - '(update -C to abort it)')) - m, a, r, d = im.repo.status()[:4] - if m or a or r or d: - raise util.Abort(_('working directory has uncommitted changes')) - - rc = im.unpickle(source) - if not rc: - status(im) - return rc - -def merge_(im, filename=None, auto=False): - success = True - if auto and not filename: - for fn in im.remaining(): - rc = im.filemerge(fn, interactive=False) - if rc: - success = False - else: - im.resolve([fn]) - if success: - im.ui.write('all conflicts resolved\n') - else: - status(im) - return 0 - - if not filename: - filename = im.next() - if not filename: - im.ui.write('all conflicts resolved\n') - return 0 - - rc = im.filemerge(filename, interactive=not auto) - if not rc: - im.resolve([filename]) - if not im.next(): - im.ui.write('all conflicts resolved\n') - return rc - -def next(im): - n = im.next() - if n: - im.ui.write('%s\n' % n) - else: - im.ui.write('all conflicts resolved\n') - return 0 - -def resolve(im, *files): - if not files: - raise util.Abort(_('resolve requires at least one filename')) - return im.resolve(files) - -def save(im, dest): - return im.pickle(dest) - -def status(im, **opts): - if not opts.get('resolved') and not opts.get('unresolved'): - opts['resolved'] = True - opts['unresolved'] = True - - if im.ui.verbose: - p1, p2 = [short(p.node()) for p in im.wctx.parents()] - im.ui.note(_('merging %s and %s\n') % (p1, p2)) - - conflicts = im.conflicts.keys() - conflicts.sort() - remaining = dict.fromkeys(im.remaining()) - st = [] - for fn in conflicts: - if opts.get('no_status'): - mode = '' - elif fn in remaining: - mode = 'U ' - else: - mode = 'R ' - if ((opts.get('resolved') and fn not in remaining) - or (opts.get('unresolved') and fn in remaining)): - st.append((mode, fn)) - st.sort() - for (mode, fn) in st: - if im.ui.verbose: - fo, fd = im.conflicts[fn] - if fd != fn: - fn = '%s (%s)' % (fn, fd) - im.ui.write('%s%s\n' % (mode, fn)) - if opts.get('unresolved') and not remaining: - im.ui.write(_('all conflicts resolved\n')) - - return 0 - -def unresolve(im, *files): - if not files: - raise util.Abort(_('unresolve requires at least one filename')) - return im.unresolve(files) - -subcmdtable = { - 'load': (load, []), - 'merge': - (merge_, - [('a', 'auto', None, _('automatically resolve if possible'))]), - 'next': (next, []), - 'resolve': (resolve, []), - 'save': (save, []), - 'status': - (status, - [('n', 'no-status', None, _('hide status prefix')), - ('', 'resolved', None, _('only show resolved conflicts')), - ('', 'unresolved', None, _('only show unresolved conflicts'))]), - 'unresolve': (unresolve, []) -} - -def dispatch_(im, args, opts): - def complete(s, choices): - candidates = [] - for choice in choices: - if choice.startswith(s): - candidates.append(choice) - return candidates - - c, args = args[0], list(args[1:]) - cmd = complete(c, subcmdtable.keys()) - if not cmd: - raise cmdutil.UnknownCommand('imerge ' + c) - if len(cmd) > 1: - cmd.sort() - raise cmdutil.AmbiguousCommand('imerge ' + c, cmd) - cmd = cmd[0] - - func, optlist = subcmdtable[cmd] - opts = {} - try: - args = fancyopts.fancyopts(args, optlist, opts) - return func(im, *args, **opts) - except fancyopts.getopt.GetoptError, inst: - raise dispatch.ParseError('imerge', '%s: %s' % (cmd, inst)) - except TypeError: - raise dispatch.ParseError('imerge', _('%s: invalid arguments') % cmd) - -def imerge(ui, repo, *args, **opts): - '''interactive merge - - imerge lets you split a merge into pieces. When you start a merge - with imerge, the names of all files with conflicts are recorded. - You can then merge any of these files, and if the merge is - successful, they will be marked as resolved. When all files are - resolved, the merge is complete. - - If no merge is in progress, hg imerge [rev] will merge the working - directory with rev (defaulting to the other head if the repository - only has two heads). You may also resume a saved merge with - hg imerge load . - - If a merge is in progress, hg imerge will default to merging the - next unresolved file. - - The following subcommands are available: - - status: - show the current state of the merge - options: - -n --no-status: do not print the status prefix - --resolved: only print resolved conflicts - --unresolved: only print unresolved conflicts - next: - show the next unresolved file merge - merge []: - merge . If the file merge is successful, the file will be - recorded as resolved. If no file is given, the next unresolved - file will be merged. - resolve ...: - mark files as successfully merged - unresolve ...: - mark files as requiring merging. - save : - save the state of the merge to a file to be resumed elsewhere - load : - load the state of the merge from a file created by save - ''' - - im = Imerge(ui, repo) - - if im.merging(): - im.resume() - else: - rev = opts.get('rev') - if rev and args: - raise util.Abort(_('please specify just one revision')) - - if len(args) == 2 and args[0] == 'load': - pass - else: - if args: - rev = args[0] - im.start(rev=rev) - if opts.get('auto'): - args = ['merge', '--auto'] - else: - args = ['status'] - - if not args: - args = ['merge'] - - return dispatch_(im, args, opts) - -cmdtable = { - '^imerge': - (imerge, - [('r', 'rev', '', _('revision to merge')), - ('a', 'auto', None, _('automatically merge where possible'))], - _('hg imerge [command]')) -} diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/keyword.py --- a/hgext/keyword.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/keyword.py Fri Feb 27 08:13:42 2009 -0600 @@ -137,7 +137,7 @@ templatefilters.filters['utcdate'] = utcdate self.ct = cmdutil.changeset_templater(self.ui, self.repo, - False, '', False) + False, None, '', False) def substitute(self, data, path, ctx, subfunc): '''Replaces keywords in data with expanded template.''' @@ -425,14 +425,10 @@ keyword substitutions. Monkeypatches patch and webcommands.''' - try: - if (not repo.local() or not kwtools['inc'] - or kwtools['hgcmd'] in nokwcommands.split() - or '.hg' in util.splitpath(repo.root) - or repo._url.startswith('bundle:')): - return - except AttributeError: - pass + if (not hasattr(repo, 'dirstate') or not kwtools['inc'] + or kwtools['hgcmd'] in nokwcommands.split() + or '.hg' in util.splitpath(repo.root)): + return kwtools['templater'] = kwt = kwtemplater(ui, repo) diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/mq.py --- a/hgext/mq.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/mq.py Fri Feb 27 08:13:42 2009 -0600 @@ -30,10 +30,9 @@ ''' from mercurial.i18n import _ -from mercurial.node import bin, hex, short -from mercurial.repo import RepoError -from mercurial import commands, cmdutil, hg, patch, revlog, util -from mercurial import repair, extensions, url +from mercurial.node import bin, hex, short, nullid, nullrev +from mercurial import commands, cmdutil, hg, patch, util +from mercurial import repair, extensions, url, error import os, sys, re, errno commands.norepo += " qclone" @@ -428,16 +427,16 @@ def qparents(self, repo, rev=None): if rev is None: (p1, p2) = repo.dirstate.parents() - if p2 == revlog.nullid: + if p2 == nullid: return p1 if len(self.applied) == 0: return None - return revlog.bin(self.applied[-1].rev) + return bin(self.applied[-1].rev) pp = repo.changelog.parents(rev) - if pp[1] != revlog.nullid: + if pp[1] != nullid: arevs = [ x.rev for x in self.applied ] - p0 = revlog.hex(pp[0]) - p1 = revlog.hex(pp[1]) + p0 = hex(pp[0]) + p1 = hex(pp[1]) if p0 in arevs: return pp[0] if p1 in arevs: @@ -455,7 +454,7 @@ pname = ".hg.patches.merge.marker" n = repo.commit(None, '[mq]: merge marker', user=None, force=1) self.removeundo(repo) - self.applied.append(statusentry(revlog.hex(n), pname)) + self.applied.append(statusentry(hex(n), pname)) self.applied_dirty = 1 head = self.qparents(repo) @@ -473,10 +472,10 @@ if not info: self.ui.warn(_("patch %s is not applied\n") % patch) return (1, None) - rev = revlog.bin(info[1]) + rev = bin(info[1]) (err, head) = self.mergeone(repo, mergeq, head, patch, rev) if head: - self.applied.append(statusentry(revlog.hex(head), patch)) + self.applied.append(statusentry(hex(head), patch)) self.applied_dirty = 1 if err: return (err, head) @@ -552,9 +551,13 @@ message.append(_("\nimported patch %s") % patchname) message = '\n'.join(message) - (patcherr, files, fuzz) = self.patch(repo, pf) - all_files.update(files) - patcherr = not patcherr + if ph.haspatch: + (patcherr, files, fuzz) = self.patch(repo, pf) + all_files.update(files) + patcherr = not patcherr + else: + self.ui.warn(_("patch %s is empty\n") % patchname) + patcherr, files, fuzz = 0, [], 0 if merge and files: # Mark as removed/merged and update dirstate parent info @@ -581,15 +584,11 @@ raise util.Abort(_("repo commit failed")) if update_status: - self.applied.append(statusentry(revlog.hex(n), patchname)) + self.applied.append(statusentry(hex(n), patchname)) if patcherr: - if not ph.haspatch: - self.ui.warn(_("patch %s is empty\n") % patchname) - err = 0 - else: - self.ui.warn(_("patch failed, rejects left in working dir\n")) - err = 1 + self.ui.warn(_("patch failed, rejects left in working dir\n")) + err = 1 break if fuzz and strict: @@ -613,7 +612,7 @@ for rev in util.sort(revs): if rev < firstrev: raise util.Abort(_('revision %d is not managed') % rev) - base = revlog.bin(self.applied[appliedbase].rev) + base = bin(self.applied[appliedbase].rev) node = repo.changelog.node(rev) if node != base: raise util.Abort(_('cannot delete revision %d above ' @@ -658,7 +657,7 @@ if appliedbase >= len(self.applied): raise util.Abort(_("revision %d is not managed") % rev) - base = revlog.bin(self.applied[appliedbase].rev) + base = bin(self.applied[appliedbase].rev) node = repo.changelog.node(rev) if node != base: raise util.Abort(_("cannot delete revision %d above " @@ -681,7 +680,7 @@ def check_toppatch(self, repo): if len(self.applied) > 0: - top = revlog.bin(self.applied[-1].rev) + top = bin(self.applied[-1].rev) pp = repo.dirstate.parents() if top not in pp: raise util.Abort(_("working directory revision is not qtip")) @@ -751,7 +750,7 @@ raise util.Abort(_("repo commit failed")) try: self.full_series[insert:insert] = [patchfn] - self.applied.append(statusentry(revlog.hex(n), patchfn)) + self.applied.append(statusentry(hex(n), patchfn)) self.parse_series() self.series_dirty = 1 self.applied_dirty = 1 @@ -963,10 +962,10 @@ raise top = self.applied[-1].name if ret[0]: - self.ui.write( - "Errors during apply, please fix and refresh %s\n" % top) + self.ui.write(_("errors during apply, please fix and " + "refresh %s\n") % top) else: - self.ui.write("Now at: %s\n" % top) + self.ui.write(_("now at: %s\n") % top) return ret[0] finally: del wlock @@ -993,38 +992,49 @@ self.ui.warn(_("no patches applied\n")) return not all + if all: + start = 0 + elif patch: + start = info[0] + 1 + else: + start = len(self.applied) - 1 + + if start >= len(self.applied): + self.ui.warn(_("qpop: %s is already at the top\n") % patch) + return + if not update: parents = repo.dirstate.parents() - rr = [ revlog.bin(x.rev) for x in self.applied ] + rr = [ bin(x.rev) for x in self.applied ] for p in parents: if p in rr: self.ui.warn(_("qpop: forcing dirstate update\n")) update = True + else: + parents = [p.hex() for p in repo[None].parents()] + needupdate = False + for entry in self.applied[start:]: + if entry.rev in parents: + needupdate = True + break + update = needupdate if not force and update: self.check_localchanges(repo) - self.applied_dirty = 1; + self.applied_dirty = 1 end = len(self.applied) - if not patch: - if all: - popi = 0 - else: - popi = len(self.applied) - 1 - else: - popi = info[0] + 1 - if popi >= end: - self.ui.warn(_("qpop: %s is already at the top\n") % patch) - return - info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name] - - start = info[0] - rev = revlog.bin(info[1]) - + rev = bin(self.applied[start].rev) if update: top = self.check_toppatch(repo) - if repo.changelog.heads(rev) != [revlog.bin(self.applied[-1].rev)]: + try: + heads = repo.changelog.heads(rev) + except error.LookupError: + node = short(rev) + raise util.Abort(_('trying to pop unknown node %s') % node) + + if heads != [bin(self.applied[-1].rev)]: raise util.Abort(_("popping would remove a revision not " "managed by this patch queue")) @@ -1052,20 +1062,20 @@ try: os.removedirs(os.path.dirname(repo.wjoin(f))) except: pass repo.dirstate.forget(f) - repo.dirstate.setparents(qp, revlog.nullid) + repo.dirstate.setparents(qp, nullid) del self.applied[start:end] self.strip(repo, rev, update=False, backup='strip') if len(self.applied): - self.ui.write(_("Now at: %s\n") % self.applied[-1].name) + self.ui.write(_("now at: %s\n") % self.applied[-1].name) else: - self.ui.write(_("Patch queue now empty\n")) + self.ui.write(_("patch queue now empty\n")) finally: del wlock def diff(self, repo, pats, opts): top = self.check_toppatch(repo) if not top: - self.ui.write(_("No patches applied\n")) + self.ui.write(_("no patches applied\n")) return qp = self.qparents(repo, top) self._diffopts = patch.diffopts(self.ui, opts) @@ -1073,7 +1083,7 @@ def refresh(self, repo, pats=None, **opts): if len(self.applied) == 0: - self.ui.write(_("No patches applied\n")) + self.ui.write(_("no patches applied\n")) return 1 msg = opts.get('msg', '').rstrip() newuser = opts.get('user') @@ -1084,7 +1094,7 @@ try: self.check_toppatch(repo) (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name) - top = revlog.bin(top) + top = bin(top) if repo.changelog.heads(top) != [top]: raise util.Abort(_("cannot refresh a revision with children")) cparents = repo.changelog.parents(top) @@ -1258,7 +1268,7 @@ patchf.rename() n = repo.commit(match.files(), message, user, ph.date, match=match, force=1) - self.applied.append(statusentry(revlog.hex(n), patchfn)) + self.applied.append(statusentry(hex(n), patchfn)) except: ctx = repo[cparents[0]] repo.dirstate.rebuild(ctx.node(), ctx.manifest()) @@ -1446,7 +1456,7 @@ if not n: self.ui.warn(_("repo commit failed\n")) return 1 - self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line')) + self.applied.append(statusentry(hex(n),'.hg.patches.save.line')) self.applied_dirty = 1 self.removeundo(repo) @@ -1524,14 +1534,14 @@ raise util.Abort(_('revision %d is the root of more than one ' 'branch') % rev[-1]) if self.applied: - base = revlog.hex(repo.changelog.node(rev[0])) + base = hex(repo.changelog.node(rev[0])) if base in [n.rev for n in self.applied]: raise util.Abort(_('revision %d is already managed') % rev[0]) - if heads != [revlog.bin(self.applied[-1].rev)]: + if heads != [bin(self.applied[-1].rev)]: raise util.Abort(_('revision %d is not the parent of ' 'the queue') % rev[0]) - base = repo.changelog.rev(revlog.bin(self.applied[0].rev)) + base = repo.changelog.rev(bin(self.applied[0].rev)) lastparent = repo.changelog.parentrevs(base)[0] else: if heads != [repo.changelog.node(rev[0])]: @@ -1545,7 +1555,7 @@ for r in rev: p1, p2 = repo.changelog.parentrevs(r) n = repo.changelog.node(r) - if p2 != revlog.nullrev: + if p2 != nullrev: raise util.Abort(_('cannot import merge revision %d') % r) if lastparent and lastparent != r: raise util.Abort(_('revision %d is not the parent of %d') @@ -1563,7 +1573,7 @@ patch.export(repo, [n], fp=patchf, opts=self.diffopts()) patchf.close() - se = statusentry(revlog.hex(n), patchname) + se = statusentry(hex(n), patchname) self.applied.insert(0, se) added.append(patchname) @@ -1602,7 +1612,7 @@ index = self.full_series_end() + i self.full_series[index:index] = [patchname] self.parse_series() - self.ui.warn("adding %s to series file\n" % patchname) + self.ui.warn(_("adding %s to series file\n") % patchname) i += 1 added.append(patchname) patchname = None @@ -1727,16 +1737,19 @@ if dest is None: dest = hg.defaultdest(source) sr = hg.repository(ui, ui.expandpath(source)) - patchespath = opts['patches'] or patchdir(sr) + if opts['patches']: + patchespath = ui.expandpath(opts['patches']) + else: + patchespath = patchdir(sr) try: pr = hg.repository(ui, patchespath) - except RepoError: + except error.RepoError: raise util.Abort(_('versioned patch repository not found' ' (see qinit -c)')) qbase, destrev = None, None if sr.local(): if sr.mq.applied: - qbase = revlog.bin(sr.mq.applied[0].rev) + qbase = bin(sr.mq.applied[0].rev) if not hg.islocal(dest): heads = dict.fromkeys(sr.heads()) for h in sr.heads(qbase): @@ -1746,7 +1759,7 @@ elif sr.capable('lookup'): try: qbase = sr.lookup('qbase') - except RepoError: + except error.RepoError: pass ui.note(_('cloning main repo\n')) sr, dr = hg.clone(ui, sr.url(), dest, @@ -1786,7 +1799,7 @@ return q.qseries(repo, start=t-1, length=1, status='A', summary=opts.get('summary')) else: - ui.write("No patches applied\n") + ui.write(_("no patches applied\n")) return 1 def next(ui, repo, **opts): @@ -1794,7 +1807,7 @@ q = repo.mq end = q.series_end() if end == len(q.series): - ui.write("All patches applied\n") + ui.write(_("all patches applied\n")) return 1 return q.qseries(repo, start=end, length=1, summary=opts.get('summary')) @@ -1803,10 +1816,10 @@ q = repo.mq l = len(q.applied) if l == 1: - ui.write("Only one patch applied\n") + ui.write(_("only one patch applied\n")) return 1 if not l: - ui.write("No patches applied\n") + ui.write(_("no patches applied\n")) return 1 return q.qseries(repo, start=l-2, length=1, status='A', summary=opts.get('summary')) @@ -1870,7 +1883,7 @@ message = cmdutil.logmessage(opts) if opts['edit']: if not q.applied: - ui.write(_("No patches applied\n")) + ui.write(_("no patches applied\n")) return 1 if message: raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) @@ -1980,13 +1993,10 @@ With no arguments, print the currently active guards. With arguments, set guards for the named patch. - - To set a negative guard "-foo" on topmost patch ("--" is needed so - hg will not interpret "-foo" as an option): - hg qguard -- -foo + NOTE: Specifying negative guards now requires '--'. To set guards on another patch: - hg qguard other.patch +2.6.17 -stable + hg qguard -- other.patch +2.6.17 -stable ''' def status(idx): guards = q.series_guards[idx] or ['unguarded'] @@ -2018,14 +2028,14 @@ status(q.series.index(q.lookup(patch))) def header(ui, repo, patch=None): - """Print the header of the topmost or specified patch""" + """print the header of the topmost or specified patch""" q = repo.mq if patch: patch = q.lookup(patch) else: if not q.applied: - ui.write('No patches applied\n') + ui.write('no patches applied\n') return 1 patch = q.lookup('qtip') ph = repo.mq.readheaders(patch) @@ -2112,7 +2122,7 @@ patch = q.lookup(patch) else: if not q.applied: - ui.write(_('No patches applied\n')) + ui.write(_('no patches applied\n')) return patch = q.lookup('qtip') absdest = q.join(name) @@ -2126,7 +2136,7 @@ raise util.Abort(_('A patch named %s already exists in the series file') % name) if ui.verbose: - ui.write('Renaming %s to %s\n' % (patch, name)) + ui.write('renaming %s to %s\n' % (patch, name)) i = q.find_series(patch) guards = q.guard_re.findall(q.full_series[i]) q.full_series[i] = name + ''.join([' #' + g for g in guards]) @@ -2211,9 +2221,9 @@ p = repo.dirstate.parents() cl = repo.changelog update = True - if p[0] == revlog.nullid: + if p[0] == nullid: update = False - elif p[1] == revlog.nullid and rev != cl.ancestor(p[0], rev): + elif p[1] == nullid and rev != cl.ancestor(p[0], rev): update = False elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)): update = False @@ -2356,7 +2366,7 @@ class mqrepo(repo.__class__): def abort_if_wdir_patched(self, errmsg, force=False): if self.mq.applied and not force: - parent = revlog.hex(self.dirstate.parents()[0]) + parent = hex(self.dirstate.parents()[0]) if parent in [s.rev for s in self.mq.applied]: raise util.Abort(errmsg) @@ -2386,11 +2396,11 @@ if not q.applied: return tagscache - mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied] + mqtags = [(bin(patch.rev), patch.name) for patch in q.applied] if mqtags[-1][0] not in self.changelog.nodemap: self.ui.warn(_('mq status file refers to unknown node %s\n') - % revlog.short(mqtags[-1][0])) + % short(mqtags[-1][0])) return tagscache mqtags.append((mqtags[-1][0], 'qtip')) @@ -2411,10 +2421,10 @@ return super(mqrepo, self)._branchtags(partial, lrev) cl = self.changelog - qbasenode = revlog.bin(q.applied[0].rev) + qbasenode = bin(q.applied[0].rev) if qbasenode not in cl.nodemap: self.ui.warn(_('mq status file refers to unknown node %s\n') - % revlog.short(qbasenode)) + % short(qbasenode)) return super(mqrepo, self)._branchtags(partial, lrev) qbase = cl.rev(qbasenode) @@ -2486,7 +2496,7 @@ (guard, [('l', 'list', None, _('list all patches and guards')), ('n', 'none', None, _('drop all guards'))], - _('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')), + _('hg qguard [-l] [-n] -- [PATCH] [+GUARD]... [-GUARD]...')), 'qheader': (header, [], _('hg qheader [PATCH]')), "^qimport": (qimport, diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/notify.py --- a/hgext/notify.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/notify.py Fri Feb 27 08:13:42 2009 -0600 @@ -113,7 +113,7 @@ template = (self.ui.config('notify', hooktype) or self.ui.config('notify', 'template')) self.t = cmdutil.changeset_templater(self.ui, self.repo, - False, mapfile, False) + False, None, mapfile, False) if not mapfile and not template: template = deftemplates.get(hooktype) or single_template if template: @@ -147,7 +147,6 @@ def subscribers(self): '''return list of email addresses of subscribers to this repo.''' - subs = {} for user, pats in self.ui.configitems('usersubs'): for pat in pats.split(','): @@ -164,20 +163,18 @@ def url(self, path=None): return self.ui.config('web', 'baseurl') + (path or self.root) - def node(self, node): + def node(self, ctx): '''format one changeset.''' - - self.t.show(self.repo[node], changes=self.repo.changelog.read(node), + self.t.show(ctx, changes=ctx.changeset(), baseurl=self.ui.config('web', 'baseurl'), - root=self.repo.root, - webroot=self.root) + root=self.repo.root, webroot=self.root) def skipsource(self, source): '''true if incoming changes from this source should be skipped.''' ok_sources = self.ui.config('notify', 'sources', 'serve').split() return source not in ok_sources - def send(self, node, count, data): + def send(self, ctx, count, data): '''send message.''' p = email.Parser.Parser() @@ -196,40 +193,33 @@ for k, v in headers: msg[k] = v - def fix_subject(subject): - '''try to make subject line exist and be useful.''' - - if not subject: - if count > 1: - subject = _('%s: %d new changesets') % (self.root, count) - else: - changes = self.repo.changelog.read(node) - s = changes[4].lstrip().split('\n', 1)[0].rstrip() - subject = '%s: %s' % (self.root, s) - maxsubject = int(self.ui.config('notify', 'maxsubject', 67)) - if maxsubject and len(subject) > maxsubject: - subject = subject[:maxsubject-3] + '...' - msg['Subject'] = mail.headencode(self.ui, subject, - self.charsets, self.test) + msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2") - def fix_sender(sender): - '''try to make message have proper sender.''' + # try to make subject line exist and be useful + if not subject: + if count > 1: + subject = _('%s: %d new changesets') % (self.root, count) + else: + s = ctx.description().lstrip().split('\n', 1)[0].rstrip() + subject = '%s: %s' % (self.root, s) + maxsubject = int(self.ui.config('notify', 'maxsubject', 67)) + if maxsubject and len(subject) > maxsubject: + subject = subject[:maxsubject-3] + '...' + msg['Subject'] = mail.headencode(self.ui, subject, + self.charsets, self.test) - if not sender: - sender = self.ui.config('email', 'from') or self.ui.username() - if '@' not in sender or '@localhost' in sender: - sender = self.fixmail(sender) - msg['From'] = mail.addressencode(self.ui, sender, - self.charsets, self.test) + # try to make message have proper sender + if not sender: + sender = self.ui.config('email', 'from') or self.ui.username() + if '@' not in sender or '@localhost' in sender: + sender = self.fixmail(sender) + msg['From'] = mail.addressencode(self.ui, sender, + self.charsets, self.test) - msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2") - fix_subject(subject) - fix_sender(sender) - - msg['X-Hg-Notification'] = 'changeset ' + short(node) + msg['X-Hg-Notification'] = 'changeset %s' % ctx if not msg['Message-Id']: msg['Message-Id'] = ('' % - (short(node), int(time.time()), + (ctx, int(time.time()), hash(self.repo.root), socket.getfqdn())) msg['To'] = ', '.join(self.subs) @@ -244,10 +234,11 @@ mail.sendmail(self.ui, util.email(msg['From']), self.subs, msgtext) - def diff(self, node, ref): + def diff(self, ctx, ref=None): + maxdiff = int(self.ui.config('notify', 'maxdiff', 300)) - prev = self.repo.changelog.parents(node)[0] - + prev = ctx.parents()[0].node() + ref = ref and ref.node() or ctx.node() chunks = patch.diff(self.repo, prev, ref, opts=patch.diffopts(self.ui)) difflines = ''.join(chunks).splitlines() @@ -256,14 +247,16 @@ # s may be nil, don't include the header if it is if s: self.ui.write('\ndiffstat:\n\n%s' % s) + if maxdiff == 0: return - if maxdiff > 0 and len(difflines) > maxdiff: - self.ui.write(_('\ndiffs (truncated from %d to %d lines):\n\n') % - (len(difflines), maxdiff)) + elif maxdiff > 0 and len(difflines) > maxdiff: + msg = _('\ndiffs (truncated from %d to %d lines):\n\n') + self.ui.write(msg % (len(difflines), maxdiff)) difflines = difflines[:maxdiff] elif difflines: self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines)) + self.ui.write("\n".join(difflines)) def hook(ui, repo, hooktype, node=None, source=None, **kwargs): @@ -271,26 +264,28 @@ if used as changegroup hook, send one email for all changesets in changegroup. else send one email per changeset.''' + n = notifier(ui, repo, hooktype) + ctx = repo[node] + if not n.subs: ui.debug(_('notify: no subscribers to repo %s\n') % n.root) return if n.skipsource(source): - ui.debug(_('notify: changes have source "%s" - skipping\n') % - source) + ui.debug(_('notify: changes have source "%s" - skipping\n') % source) return - node = bin(node) + ui.pushbuffer() if hooktype == 'changegroup': - start = repo[node].rev() - end = len(repo) + start, end = ctx.rev(), len(repo) count = end - start for rev in xrange(start, end): - n.node(repo[rev].node()) - n.diff(node, repo.changelog.tip()) + n.node(repo[rev]) + n.diff(ctx, repo['tip']) else: count = 1 - n.node(node) - n.diff(node, node) + n.node(ctx) + n.diff(ctx) + data = ui.popbuffer() - n.send(node, count, data) + n.send(ctx, count, data) diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/parentrevspec.py --- a/hgext/parentrevspec.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/parentrevspec.py Fri Feb 27 08:13:42 2009 -0600 @@ -24,6 +24,7 @@ foo~2 = foo^1^1 = foo^^ = first parent of first parent of foo ''' import mercurial.repo +from mercurial import error def reposetup(ui, repo): if not repo.local(): @@ -34,7 +35,7 @@ try: _super = super(parentrevspecrepo, self) return _super.lookup(key) - except mercurial.repo.RepoError: + except error.RepoError: pass circ = key.find('^') @@ -50,7 +51,7 @@ base = key[:end] try: node = _super.lookup(base) - except mercurial.repo.RepoError: + except error.RepoError: # eek - reraise the first error return _super.lookup(key) diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/patchbomb.py --- a/hgext/patchbomb.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/patchbomb.py Fri Feb 27 08:13:42 2009 -0600 @@ -9,8 +9,7 @@ The remainder of the changeset description. - [Optional] If the diffstat program is installed, the result of - running diffstat on the patch. + [Optional] The result of running diffstat on the patch. The patch itself, as generated by "hg export". @@ -59,7 +58,13 @@ % formail -s sendmail -bm -t < mbox -That should be all. Now your patchbomb is on its way out.''' +That should be all. Now your patchbomb is on its way out. + +You can also either configure the method option in the email section +to be a sendmail compatable mailer or fill out the [smtp] section so +that the patchbomb extension can automatically send patchbombs directly +from the commandline. See the [email] and [smtp] sections in hgrc(5) +for details.''' import os, errno, socket, tempfile, cStringIO import email.MIMEMultipart, email.MIMEBase @@ -68,19 +73,6 @@ from mercurial.i18n import _ from mercurial.node import bin -class exportee: - def __init__(self, container): - self.lines = [] - self.container = container - self.name = 'email' - - def write(self, data): - self.lines.append(data) - - def close(self): - self.container.append(''.join(self.lines).split('\n')) - self.lines = [] - def prompt(ui, prompt, default=None, rest=': ', empty_ok=False): if not ui.interactive: return default @@ -99,16 +91,12 @@ def cdiffstat(ui, summary, patchlines): s = patch.diffstat(patchlines) - if s: - if summary: - ui.write(summary, '\n') - ui.write(s, '\n') - ans = prompt(ui, _('Does the diffstat above look okay? '), 'y') - if not ans.lower().startswith('y'): - raise util.Abort(_('diffstat rejected')) - elif s is None: - ui.warn(_('no diffstat information available\n')) - s = '' + if summary: + ui.write(summary, '\n') + ui.write(s, '\n') + ans = prompt(ui, _('does the diffstat above look okay? '), 'y') + if not ans.lower().startswith('y'): + raise util.Abort(_('diffstat rejected')) return s def makepatch(ui, repo, patch, opts, _charsets, idx, total, patchname=None): @@ -239,6 +227,13 @@ o = repo.changelog.nodesbetween(o, revs or None)[0] return [str(repo.changelog.rev(r)) for r in o] + def getpatches(revs): + for r in cmdutil.revrange(repo, revs): + output = cStringIO.StringIO() + p = patch.export(repo, [r], fp=output, + opts=patch.diffopts(ui, opts)) + yield output.getvalue().split('\n') + def getbundle(dest): tmpdir = tempfile.mkdtemp(prefix='hg-email-bundle-') tmpfn = os.path.join(tmpdir, 'bundle') @@ -308,7 +303,7 @@ % len(patches)) name = None - for p, i in zip(patches, xrange(len(patches))): + for i, p in enumerate(patches): jumbo.extend(p) if patchnames: name = patchnames[i] @@ -360,18 +355,14 @@ ui.config('patchbomb', 'from') or prompt(ui, 'From', ui.username())) + # internal option used by pbranches patches = opts.get('patches') if patches: msgs = getpatchmsgs(patches, opts.get('patchnames')) elif opts.get('bundle'): msgs = getbundlemsgs(getbundle(dest)) else: - patches = [] - commands.export(ui, repo, *revs, **{'output': exportee(patches), - 'switch_parent': False, - 'text': None, - 'git': opts.get('git')}) - msgs = getpatchmsgs(patches) + msgs = getpatchmsgs(list(getpatches(revs))) def getaddrs(opt, prpt, default = None): addrs = opts.get(opt) or (ui.config('email', opt) or diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/purge.py --- a/hgext/purge.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/purge.py Fri Feb 27 08:13:42 2009 -0600 @@ -32,28 +32,26 @@ import os def purge(ui, repo, *dirs, **opts): - '''removes files not tracked by mercurial + '''removes files not tracked by Mercurial - Delete files not known to mercurial, this is useful to test local and - uncommitted changes in the otherwise clean source tree. + Delete files not known to Mercurial. This is useful to test local and + uncommitted changes in an otherwise-clean source tree. This means that purge will delete: - Unknown files: files marked with "?" by "hg status" - - Ignored files: files usually ignored by Mercurial because they match - a pattern in a ".hgignore" file - Empty directories: in fact Mercurial ignores directories unless they contain files under source control managment But it will leave untouched: - - Unmodified tracked files - - Modified tracked files + - Modified and unmodified tracked files + - Ignored files (unless --all is specified) - New files added to the repository (with "hg add") If directories are given on the command line, only files in these directories are considered. - Be careful with purge, you could irreversibly delete some files you + Be careful with purge, as you could irreversibly delete some files you forgot to add to the repository. If you only want to print the list of - files that this program would delete use the --print option. + files that this program would delete, use the --print option. ''' act = not opts['print'] eol = '\n' @@ -64,7 +62,7 @@ def remove(remove_func, name): if act: try: - remove_func(os.path.join(repo.root, name)) + remove_func(repo.wjoin(name)) except OSError: m = _('%s cannot be removed') % name if opts['abort_on_err']: diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/rebase.py --- a/hgext/rebase.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/rebase.py Fri Feb 27 08:13:42 2009 -0600 @@ -13,7 +13,7 @@ http://www.selenic.com/mercurial/wiki/index.cgi/RebaseProject ''' -from mercurial import util, repair, merge, cmdutil, dispatch, commands +from mercurial import util, repair, merge, cmdutil, commands, error from mercurial import extensions, ancestor from mercurial.commands import templateopts from mercurial.node import nullrev @@ -34,7 +34,7 @@ if not first: ancestor.ancestor = newancestor else: - repo.ui.debug(_("First revision, do not change ancestor\n")) + repo.ui.debug(_("first revision, do not change ancestor\n")) stats = merge.update(repo, rev, True, True, False) return stats @@ -67,21 +67,21 @@ extrafn = opts.get('extrafn') if opts.get('keepbranches', None): if extrafn: - raise dispatch.ParseError('rebase', - _('cannot use both keepbranches and extrafn')) + raise error.ParseError( + 'rebase', _('cannot use both keepbranches and extrafn')) def extrafn(ctx, extra): extra['branch'] = ctx.branch() if contf or abortf: if contf and abortf: - raise dispatch.ParseError('rebase', - _('cannot use both abort and continue')) + raise error.ParseError('rebase', + _('cannot use both abort and continue')) if collapsef: - raise dispatch.ParseError('rebase', - _('cannot use collapse with continue or abort')) + raise error.ParseError( + 'rebase', _('cannot use collapse with continue or abort')) if (srcf or basef or destf): - raise dispatch.ParseError('rebase', + raise error.ParseError('rebase', _('abort and continue do not allow specifying revisions')) originalwd, target, state, collapsef, external = restorestatus(repo) @@ -90,8 +90,8 @@ return else: if srcf and basef: - raise dispatch.ParseError('rebase', _('cannot specify both a ' - 'revision and a base')) + raise error.ParseError('rebase', _('cannot specify both a ' + 'revision and a base')) cmdutil.bail_if_changed(repo) result = buildstate(repo, destf, srcf, basef, collapsef) if result: @@ -281,7 +281,7 @@ f.write(repo[target].hex() + '\n') f.write(repo[external].hex() + '\n') f.write('%d\n' % int(collapse)) - for d, v in state.items(): + for d, v in state.iteritems(): oldrev = repo[d].hex() newrev = repo[v].hex() f.write("%s:%s\n" % (oldrev, newrev)) @@ -400,7 +400,9 @@ 'Call rebase after pull if the latter has been invoked with --rebase' if opts.get('rebase'): if opts.get('update'): - raise util.Abort(_('--update and --rebase are not compatible')) + del opts.get['update'] + ui.debug(_('--update and --rebase are not compatible, ignoring ' + 'the update flag\n')) cmdutil.bail_if_changed(repo) revsprepull = len(repo) @@ -408,6 +410,11 @@ revspostpull = len(repo) if revspostpull > revsprepull: rebase(ui, repo, **opts) + branch = repo[None].branch() + dest = repo[branch].rev() + if dest != repo['.'].rev(): + # there was nothing to rebase we force an update + merge.update(repo, dest, False, False, False) else: orig(ui, repo, *args, **opts) diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/record.py --- a/hgext/record.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/record.py Fri Feb 27 08:13:42 2009 -0600 @@ -406,15 +406,10 @@ In the end we'll record intresting changes, and everything else will be left in place, so the user can continue his work. """ - if match.files(): - changes = None - else: - changes = repo.status(match=match)[:3] - modified, added, removed = changes - match = cmdutil.matchfiles(repo, modified + added + removed) + + changes = repo.status(match=match)[:3] diffopts = mdiff.diffopts(git=True, nodates=True) - chunks = patch.diff(repo, repo.dirstate.parents()[0], match=match, - changes=changes, opts=diffopts) + chunks = patch.diff(repo, changes=changes, opts=diffopts) fp = cStringIO.StringIO() fp.write(''.join(chunks)) fp.seek(0) @@ -428,15 +423,12 @@ try: contenders.update(dict.fromkeys(h.files())) except AttributeError: pass - newfiles = [f for f in match.files() if f in contenders] - + changed = changes[0] + changes[1] + changes[2] + newfiles = [f for f in changed if f in contenders] if not newfiles: ui.status(_('no changes to record\n')) return 0 - if changes is None: - match = cmdutil.matchfiles(repo, newfiles) - changes = repo.status(match=match) modified = dict.fromkeys(changes[0]) # 2. backup changed files, so we can restore them in the end @@ -475,7 +467,9 @@ try: ui.debug(_('applying patch\n')) ui.debug(fp.getvalue()) - patch.internalpatch(fp, ui, 1, repo.root) + pfiles = {} + patch.internalpatch(fp, ui, 1, repo.root, files=pfiles) + patch.updatedir(ui, repo, pfiles) except patch.PatchError, err: s = str(err) if s: diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/transplant.py --- a/hgext/transplant.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/transplant.py Fri Feb 27 08:13:42 2009 -0600 @@ -5,11 +5,6 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -from mercurial.i18n import _ -import os, tempfile -from mercurial import bundlerepo, changegroup, cmdutil, hg, merge -from mercurial import patch, revlog, util - '''patch transplanting tool This extension allows you to transplant patches from another branch. @@ -18,6 +13,11 @@ from a changeset hash to its hash in the source repository. ''' +from mercurial.i18n import _ +import os, tempfile +from mercurial import bundlerepo, changegroup, cmdutil, hg, merge +from mercurial import patch, revlog, util, error + class transplantentry: def __init__(self, lnode, rnode): self.lnode = lnode @@ -69,7 +69,8 @@ self.ui = ui self.path = repo.join('transplant') self.opener = util.opener(self.path) - self.transplants = transplants(self.path, 'transplants', opener=self.opener) + self.transplants = transplants(self.path, 'transplants', + opener=self.opener) def applied(self, repo, node, parent): '''returns True if a node is already an ancestor of parent @@ -109,8 +110,8 @@ parents = source.changelog.parents(node) if not opts.get('filter'): - # If the changeset parent is the same as the wdir's parent, - # just pull it. + # If the changeset parent is the same as the + # wdir's parent, just pull it. if parents[0] == p1: pulls.append(node) p1 = node @@ -124,9 +125,9 @@ domerge = False if node in merges: - # pulling all the merge revs at once would mean we couldn't - # transplant after the latest even if transplants before them - # fail. + # pulling all the merge revs at once would mean we + # couldn't transplant after the latest even if + # transplants before them fail. domerge = True if not hasnode(repo, node): repo.pull(source, heads=[node]) @@ -155,8 +156,9 @@ self.ui.status(_('%s merged at %s\n') % (revstr, revlog.short(n))) elif n: - self.ui.status(_('%s transplanted to %s\n') % (revlog.short(node), - revlog.short(n))) + self.ui.status(_('%s transplanted to %s\n') + % (revlog.short(node), + revlog.short(n))) finally: if patchfile: os.unlink(patchfile) @@ -217,7 +219,8 @@ fuzz = patch.patch(patchfile, self.ui, cwd=repo.root, files=files) if not files: - self.ui.warn(_('%s: empty changeset') % revlog.hex(node)) + self.ui.warn(_('%s: empty changeset') + % revlog.hex(node)) return None finally: files = patch.updatedir(self.ui, repo, files) @@ -231,7 +234,8 @@ p2 = node self.log(user, date, message, p1, p2, merge=merge) self.ui.write(str(inst) + '\n') - raise util.Abort(_('Fix up the merge and run hg transplant --continue')) + raise util.Abort(_('Fix up the merge and run ' + 'hg transplant --continue')) else: files = None if merge: @@ -380,7 +384,7 @@ def hasnode(repo, node): try: return repo.changelog.rev(node) != None - except revlog.RevlogError: + except error.RevlogError: return False def browserevs(ui, repo, nodes, opts): @@ -496,16 +500,19 @@ def checkopts(opts, revs): if opts.get('continue'): if filter(lambda opt: opts.get(opt), ('branch', 'all', 'merge')): - raise util.Abort(_('--continue is incompatible with branch, all or merge')) + raise util.Abort(_('--continue is incompatible with ' + 'branch, all or merge')) return if not (opts.get('source') or revs or opts.get('merge') or opts.get('branch')): - raise util.Abort(_('no source URL, branch tag or revision list provided')) + raise util.Abort(_('no source URL, branch tag or revision ' + 'list provided')) if opts.get('all'): if not opts.get('branch'): raise util.Abort(_('--all requires a branch revision')) if revs: - raise util.Abort(_('--all is incompatible with a revision list')) + raise util.Abort(_('--all is incompatible with a ' + 'revision list')) checkopts(opts, revs) @@ -553,9 +560,11 @@ revmap[int(r)] = source.lookup(r) elif opts.get('all') or not merges: if source != repo: - alltransplants = incwalk(source, incoming, branches, match=matchfn) + alltransplants = incwalk(source, incoming, branches, + match=matchfn) else: - alltransplants = transplantwalk(source, p1, branches, match=matchfn) + alltransplants = transplantwalk(source, p1, branches, + match=matchfn) if opts.get('all'): revs = alltransplants else: @@ -581,7 +590,9 @@ ('p', 'prune', [], _('skip over REV')), ('m', 'merge', [], _('merge at REV')), ('', 'log', None, _('append transplant info to log message')), - ('c', 'continue', None, _('continue last transplant session after repair')), + ('c', 'continue', None, _('continue last transplant session ' + 'after repair')), ('', 'filter', '', _('filter changesets through FILTER'))], - _('hg transplant [-s REPOSITORY] [-b BRANCH [-a]] [-p REV] [-m REV] [REV]...')) + _('hg transplant [-s REPOSITORY] [-b BRANCH [-a]] [-p REV] ' + '[-m REV] [REV]...')) } diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/win32mbcs.py --- a/hgext/win32mbcs.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/win32mbcs.py Fri Feb 27 08:13:42 2009 -0600 @@ -8,7 +8,7 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. # -"""Allow to use MBCS path with problematic encoding. +"""allow to use MBCS path with problematic encoding. Some MBCS encodings are not good for some path operations (i.e. splitting path, case conversion, etc.) with its encoded bytes. diff -r dd970a311ea8 -r 6d99ff7b79b5 hgext/zeroconf/__init__.py --- a/hgext/zeroconf/__init__.py Sun Jan 25 19:15:49 2009 +0100 +++ b/hgext/zeroconf/__init__.py Fri Feb 27 08:13:42 2009 -0600 @@ -6,6 +6,29 @@ # the GNU General Public License (version 2), incorporated herein by # reference. +'''zeroconf support for mercurial repositories + +Zeroconf enabled repositories will be announced in a network without the need +to configure a server or a service. They can be discovered without knowing +their actual IP address. + +To use the zeroconf extension add the following entry to your hgrc file: + +[extensions] +hgext.zeroconf = + +To allow other people to discover your repository using run "hg serve" in your +repository. + + $ cd test + $ hg serve + +You can discover zeroconf enabled repositories by running "hg paths". + + $ hg paths + zc-test = http://example.com:8000/test +''' + import Zeroconf, socket, time, os from mercurial import ui from mercurial import extensions @@ -29,7 +52,7 @@ # Generic method, sometimes gives useless results dumbip = socket.gethostbyaddr(socket.gethostname())[2][0] - if not dumbip.startswith('127.'): + if not dumbip.startswith('127.') and ':' not in dumbip: return dumbip # works elsewhere, but actually sends a packet diff -r dd970a311ea8 -r 6d99ff7b79b5 i18n/da.po --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i18n/da.po Fri Feb 27 08:13:42 2009 -0600 @@ -0,0 +1,8827 @@ +# Danish translations for Mercurial +# Danske oversættelser for Mercurial +# Copyright (C) 2009 Matt Mackall and others +# +# Translation dictionary: +# +# changeset ændring +# merge sammenføje +# patch rettelse +# repo(sitory) arkiv +# revision revision +# tag mærkat +# +msgid "" +msgstr "" +"Project-Id-Version: Mercurial\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-02-22 22:02+0100\n" +"PO-Revision-Date: 2009-02-22 22:05+0100\n" +"Last-Translator: \n" +"Language-Team: Danish\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, python-format +msgid " (default: %s)" +msgstr " (standard: %s)" + +msgid "OPTIONS" +msgstr "" + +msgid "COMMANDS" +msgstr "KOMMANDOER" + +msgid " options:\n" +msgstr "" + +#, python-format +msgid "" +" aliases: %s\n" +"\n" +msgstr "" +" aliaser %s:\n" +"\n" + +msgid "return tuple of (match function, list enabled)." +msgstr "" + +#, python-format +msgid "acl: %s not enabled\n" +msgstr "acl: %s er ikke slået til\n" + +#, python-format +msgid "acl: %s enabled, %d entries for user %s\n" +msgstr "acl: %s slået til, %d indgange for bruger %s\n" + +#, python-format +msgid "config error - hook type \"%s\" cannot stop incoming changesets" +msgstr "" +"konfigurationsfejl - hook type \"%s\" kan ikke stoppe indgående ændringer" + +#, python-format +msgid "acl: changes have source \"%s\" - skipping\n" +msgstr "acl: ændringer har kilde \"%s\" - springer over\n" + +#, python-format +msgid "acl: user %s denied on %s\n" +msgstr "acl: bruger %s nægtet adgang til %s\n" + +#, python-format +msgid "acl: access denied for changeset %s" +msgstr "acl: adgang nægtet til ændring %s" + +#, python-format +msgid "acl: user %s not allowed on %s\n" +msgstr "acl: bruger %s ikke tilladt på %s\n" + +#, python-format +msgid "acl: allowing changeset %s\n" +msgstr "acl: tillader ændring %s\n" + +msgid "" +"allow user-defined command aliases\n" +"\n" +"To use, create entries in your hgrc of the form\n" +"\n" +"[alias]\n" +"mycmd = cmd --args\n" +msgstr "" + +msgid "" +"defer command lookup until needed, so that extensions loaded\n" +" after alias can be aliased" +msgstr "" + +#, python-format +msgid "*** [alias] %s: command %s is unknown" +msgstr "" + +#, python-format +msgid "*** [alias] %s: command %s is ambiguous" +msgstr "" + +#, python-format +msgid "*** [alias] %s: circular dependency on %s" +msgstr "" + +#, python-format +msgid "*** [alias] %s: no definition\n" +msgstr "" + +msgid "" +"mercurial bookmarks\n" +"\n" +"Mercurial bookmarks are local moveable pointers to changesets. Every\n" +"bookmark points to a changeset identified by its hash. If you commit a\n" +"changeset that is based on a changeset that has a bookmark on it, the\n" +"bookmark is forwarded to the new changeset.\n" +"\n" +"It is possible to use bookmark names in every revision lookup (e.g. hg\n" +"merge, hg update).\n" +"\n" +"The bookmark extension offers the possiblity to have a more git-like " +"experience\n" +"by adding the following configuration option to your .hgrc:\n" +"\n" +"[bookmarks]\n" +"track.current = True\n" +"\n" +"This will cause bookmarks to track the bookmark that you are currently on, " +"and\n" +"just updates it. This is similar to git's approach of branching.\n" +msgstr "" + +msgid "" +"Parse .hg/bookmarks file and return a dictionary\n" +"\n" +" Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values\n" +" in the .hg/bookmarks file. They are read by the parse() method and\n" +" returned as a dictionary with name => hash values.\n" +"\n" +" The parsed dictionary is cached until a write() operation is done.\n" +" " +msgstr "" + +msgid "" +"Write bookmarks\n" +"\n" +" Write the given bookmark => hash dictionary to the .hg/bookmarks file\n" +" in a format equal to those of localtags.\n" +"\n" +" We also store a backup of the previous state in undo.bookmarks that\n" +" can be copied back on rollback.\n" +" " +msgstr "" + +msgid "" +"Get the current bookmark\n" +"\n" +" If we use gittishsh branches we have a current bookmark that\n" +" we are on. This function returns the name of the bookmark. It\n" +" is stored in .hg/bookmarks.current\n" +" " +msgstr "" + +msgid "" +"Set the name of the bookmark that we are currently on\n" +"\n" +" Set the name of the bookmark that we are on (hg update ).\n" +" The name is recoreded in .hg/bookmarks.current\n" +" " +msgstr "" + +msgid "" +"mercurial bookmarks\n" +"\n" +" Bookmarks are pointers to certain commits that move when\n" +" commiting. Bookmarks are local. They can be renamed, copied and\n" +" deleted. It is possible to use bookmark names in 'hg merge' and 'hg\n" +" update' to update to a given bookmark.\n" +"\n" +" You can use 'hg bookmark NAME' to set a bookmark on the current\n" +" tip with the given name. If you specify a revision using -r REV\n" +" (where REV may be an existing bookmark), the bookmark is set to\n" +" that revision.\n" +" " +msgstr "" + +msgid "a bookmark of this name does not exist" +msgstr "" + +msgid "a bookmark of the same name already exists" +msgstr "" + +msgid "new bookmark name required" +msgstr "" + +msgid "bookmark name required" +msgstr "" + +msgid "bookmark name cannot contain newlines" +msgstr "bogmærkenavn kan ikke indeholde linieskift" + +msgid "a bookmark cannot have the name of an existing branch" +msgstr "" + +msgid "" +"Strip bookmarks if revisions are stripped using\n" +" the mercurial.strip method. This usually happens during\n" +" qpush and qpop" +msgstr "" + +msgid "" +"Add a revision to the repository and\n" +" move the bookmark" +msgstr "" + +msgid "Merge bookmarks with normal tags" +msgstr "" + +msgid "" +"Set the current bookmark\n" +"\n" +" If the user updates to a bookmark we update the .hg/bookmarks.current\n" +" file.\n" +" " +msgstr "" + +msgid "force" +msgstr "" + +msgid "revision" +msgstr "" + +msgid "delete a given bookmark" +msgstr "" + +msgid "rename a given bookmark" +msgstr "" + +msgid "hg bookmarks [-d] [-m NAME] [-r NAME] [NAME]" +msgstr "" + +msgid "" +"Bugzilla integration\n" +"\n" +"This hook extension adds comments on bugs in Bugzilla when changesets\n" +"that refer to bugs by Bugzilla ID are seen. The hook does not change bug\n" +"status.\n" +"\n" +"The hook updates the Bugzilla database directly. Only Bugzilla " +"installations\n" +"using MySQL are supported.\n" +"\n" +"The hook relies on a Bugzilla script to send bug change notification " +"emails.\n" +"That script changes between Bugzilla versions; the 'processmail' script " +"used\n" +"prior to 2.18 is replaced in 2.18 and subsequent versions by\n" +"'config/sendbugmail.pl'. Note that these will be run by Mercurial as the " +"user\n" +"pushing the change; you will need to ensure the Bugzilla install file\n" +"permissions are set appropriately.\n" +"\n" +"Configuring the extension:\n" +"\n" +" [bugzilla]\n" +" host Hostname of the MySQL server holding the Bugzilla database.\n" +" db Name of the Bugzilla database in MySQL. Default 'bugs'.\n" +" user Username to use to access MySQL server. Default 'bugs'.\n" +" password Password to use to access MySQL server.\n" +" timeout Database connection timeout (seconds). Default 5.\n" +" version Bugzilla version. Specify '3.0' for Bugzilla versions 3.0 " +"and\n" +" later, '2.18' for Bugzilla versions from 2.18 and '2.16' for\n" +" versions prior to 2.18.\n" +" bzuser Fallback Bugzilla user name to record comments with, if\n" +" changeset committer cannot be found as a Bugzilla user.\n" +" bzdir Bugzilla install directory. Used by default notify.\n" +" Default '/var/www/html/bugzilla'.\n" +" notify The command to run to get Bugzilla to send bug change\n" +" notification emails. Substitutes from a map with 3 keys,\n" +" 'bzdir', 'id' (bug id) and 'user' (committer bugzilla " +"email).\n" +" Default depends on version; from 2.18 it is\n" +" \"cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %" +"(user)s\".\n" +" regexp Regular expression to match bug IDs in changeset commit " +"message.\n" +" Must contain one \"()\" group. The default expression " +"matches\n" +" 'Bug 1234', 'Bug no. 1234', 'Bug number 1234',\n" +" 'Bugs 1234,5678', 'Bug 1234 and 5678' and variations " +"thereof.\n" +" Matching is case insensitive.\n" +" style The style file to use when formatting comments.\n" +" template Template to use when formatting comments. Overrides\n" +" style if specified. In addition to the usual Mercurial\n" +" keywords, the extension specifies:\n" +" {bug} The Bugzilla bug ID.\n" +" {root} The full pathname of the Mercurial " +"repository.\n" +" {webroot} Stripped pathname of the Mercurial " +"repository.\n" +" {hgweb} Base URL for browsing Mercurial " +"repositories.\n" +" Default 'changeset {node|short} in repo {root} refers '\n" +" 'to bug {bug}.\\ndetails:\\n\\t{desc|tabindent}'\n" +" strip The number of slashes to strip from the front of {root}\n" +" to produce {webroot}. Default 0.\n" +" usermap Path of file containing Mercurial committer ID to Bugzilla " +"user\n" +" ID mappings. If specified, the file should contain one " +"mapping\n" +" per line, \"committer\"=\"Bugzilla user\". See also the\n" +" [usermap] section.\n" +"\n" +" [usermap]\n" +" Any entries in this section specify mappings of Mercurial committer ID\n" +" to Bugzilla user ID. See also [bugzilla].usermap.\n" +" \"committer\"=\"Bugzilla user\"\n" +"\n" +" [web]\n" +" baseurl Base URL for browsing Mercurial repositories. Reference from\n" +" templates as {hgweb}.\n" +"\n" +"Activating the extension:\n" +"\n" +" [extensions]\n" +" hgext.bugzilla =\n" +"\n" +" [hooks]\n" +" # run bugzilla hook on every change pulled or pushed in here\n" +" incoming.bugzilla = python:hgext.bugzilla.hook\n" +"\n" +"Example configuration:\n" +"\n" +"This example configuration is for a collection of Mercurial repositories\n" +"in /var/local/hg/repos/ used with a local Bugzilla 3.2 installation in\n" +"/opt/bugzilla-3.2.\n" +"\n" +" [bugzilla]\n" +" host=localhost\n" +" password=XYZZY\n" +" version=3.0\n" +" bzuser=unknown@domain.com\n" +" bzdir=/opt/bugzilla-3.2\n" +" template=Changeset {node|short} in {root|basename}.\\n{hgweb}/{webroot}/" +"rev/{node|short}\\n\\n{desc}\\n\n" +" strip=5\n" +"\n" +" [web]\n" +" baseurl=http://dev.domain.com/hg\n" +"\n" +" [usermap]\n" +" user@emaildomain.com=user.name@bugzilladomain.com\n" +"\n" +"Commits add a comment to the Bugzilla bug record of the form:\n" +"\n" +" Changeset 3b16791d6642 in repository-name.\n" +" http://dev.domain.com/hg/repository-name/rev/3b16791d6642\n" +"\n" +" Changeset commit comment. Bug 1234.\n" +msgstr "" + +msgid "support for bugzilla version 2.16." +msgstr "" + +#, python-format +msgid "connecting to %s:%s as %s, password %s\n" +msgstr "forbinder til %s:%s som %s, kodeord %s\n" + +msgid "run a query." +msgstr "" + +#, python-format +msgid "query: %s %s\n" +msgstr "forespørgsel: %s %s\n" + +#, python-format +msgid "failed query: %s %s\n" +msgstr "fejlet forespørgsel: %s %s\n" + +msgid "get identity of longdesc field" +msgstr "" + +msgid "unknown database schema" +msgstr "ukendt databaseskema" + +msgid "filter not-existing bug ids from list." +msgstr "" + +msgid "filter bug ids from list that already refer to this changeset." +msgstr "" + +#, python-format +msgid "bug %d already knows about changeset %s\n" +msgstr "fejl %d kender allerede til ændring %s\n" + +msgid "tell bugzilla to send mail." +msgstr "" + +msgid "telling bugzilla to send mail:\n" +msgstr "beder bugzilla om at sende mail:\n" + +#, python-format +msgid " bug %s\n" +msgstr " fejl %s\n" + +#, python-format +msgid "running notify command %s\n" +msgstr "kører notificeringskommando %s\n" + +#, python-format +msgid "bugzilla notify command %s" +msgstr "" + +msgid "done\n" +msgstr "færdig\n" + +msgid "look up numeric bugzilla user id." +msgstr "" + +#, python-format +msgid "looking up user %s\n" +msgstr "slår bruger %s op\n" + +msgid "map name of committer to bugzilla user name." +msgstr "" + +msgid "" +"see if committer is a registered bugzilla user. Return\n" +" bugzilla username and userid if so. If not, return default\n" +" bugzilla username and userid." +msgstr "" + +#, python-format +msgid "cannot find bugzilla user id for %s" +msgstr "" + +#, python-format +msgid "cannot find bugzilla user id for %s or %s" +msgstr "" + +msgid "" +"add comment to bug. try adding comment as committer of\n" +" changeset, otherwise as default bugzilla user." +msgstr "" + +msgid "support for bugzilla 2.18 series." +msgstr "" + +msgid "support for bugzilla 3.0 series." +msgstr "" + +msgid "" +"return object that knows how to talk to bugzilla version in\n" +" use." +msgstr "" + +#, python-format +msgid "bugzilla version %s not supported" +msgstr "" + +msgid "" +"find valid bug ids that are referred to in changeset\n" +" comments and that do not already have references to this\n" +" changeset." +msgstr "" + +msgid "update bugzilla bug with reference to changeset." +msgstr "" + +msgid "" +"strip leading prefix of repo root and turn into\n" +" url-safe path." +msgstr "" + +msgid "" +"changeset {node|short} in repo {root} refers to bug {bug}.\n" +"details:\n" +"\t{desc|tabindent}" +msgstr "" + +msgid "" +"add comment to bugzilla for each changeset that refers to a\n" +" bugzilla bug id. only add a comment once per bug, so same change\n" +" seen multiple times does not fill bug with duplicate data." +msgstr "" + +#, python-format +msgid "python mysql support not available: %s" +msgstr "" + +#, python-format +msgid "hook type %s does not pass a changeset id" +msgstr "" + +#, python-format +msgid "database error: %s" +msgstr "" + +msgid "" +"show the children of the given or working dir revision\n" +"\n" +" Print the children of the working directory's revisions.\n" +" If a revision is given via --rev, the children of that revision\n" +" will be printed. If a file argument is given, revision in\n" +" which the file was last changed (after the working directory\n" +" revision or the argument to --rev if given) is printed.\n" +" " +msgstr "" + +msgid "show children of the specified rev" +msgstr "" + +msgid "hg children [-r REV] [FILE]" +msgstr "" + +msgid "command to show certain statistics about revision history" +msgstr "" + +msgid "Calculate stats" +msgstr "" + +#, python-format +msgid "Revision %d is a merge, ignoring...\n" +msgstr "" + +#, python-format +msgid "\rgenerating stats: %d%%" +msgstr "" + +msgid "" +"graph count of revisions grouped by template\n" +"\n" +" Will graph count of changed lines or revisions grouped by template or\n" +" alternatively by date, if dateformat is used. In this case it will " +"override\n" +" template.\n" +"\n" +" By default statistics are counted for number of changed lines.\n" +"\n" +" Examples:\n" +"\n" +" # display count of changed lines for every committer\n" +" hg churn -t '{author|email}'\n" +"\n" +" # display daily activity graph\n" +" hg churn -f '%H' -s -c\n" +"\n" +" # display activity of developers by month\n" +" hg churn -f '%Y-%m' -s -c\n" +"\n" +" # display count of lines changed in every year\n" +" hg churn -f '%Y' -s\n" +"\n" +" The map file format used to specify aliases is fairly simple:\n" +"\n" +" " +msgstr "" +"plot antallet af revisioner grupperet efter et mønster\n" +"\n" +" Plotter antallet af ændrede linier eller antallet af revisioner\n" +" grupperet efter et mønster eller alternativt efter dato, hvis\n" +" dateformat bruges. I så tilfælde bruges mønstret ikke.\n" +"\n" +" Som udgangspunkt laves der statistik over antallet af ændrede\n" +" linier.\n" +"\n" +" Eksempler:\n" +"\n" +" # viser antaller af ændrede linier for hver bruger\n" +" hg churn -t '{author|email}'\n" +"\n" +" # viser graf over daglig aktivitet\n" +" hg churn -f '%H' -s -c\n" +"\n" +" # viser månedlig aktivitet af udviklerne\n" +" hg churn -f '%Y-%m' -s -c\n" +"\n" +" # viser antallet af linier ændret hvert år\n" +" hg churn -f '%Y' -s\n" +"\n" +" Formatet for map-filen er rimelig simpelt:\n" +"\n" +" " + +#, python-format +msgid "assuming %i character terminal\n" +msgstr "" + +msgid "count rate for the specified revision or range" +msgstr "lav statistik for de specificerede revisioner" + +msgid "count rate for revs matching date spec" +msgstr "lav statistik for revisioner som matcher dato specifikationen" + +msgid "template to group changesets" +msgstr "mønster for gruppering af ændringer" + +msgid "strftime-compatible format for grouping by date" +msgstr "strftime-kompatibelt format til gruppering efter dato" + +msgid "count rate by number of changesets" +msgstr "lav statistik efter antallet af ændringer" + +msgid "sort by key (default: sort by count)" +msgstr "sortér efter nøgle (standard: sortering efter antal)" + +msgid "file with email aliases" +msgstr "fil med email-aliaser" + +msgid "show progress" +msgstr "vis fremskridt" + +msgid "hg churn [-d DATE] [-r REV] [--aliases FILE] [--progress] [FILE]" +msgstr "hg churn [-d DATO] [-r REVISIONER] [--aliases FIL] [--progress] [FIL]" + +msgid "" +"add color output to status, qseries, and diff-related commands\n" +"\n" +"This extension modifies the status command to add color to its output to\n" +"reflect file status, the qseries command to add color to reflect patch " +"status\n" +"(applied, unapplied, missing), and to diff-related commands to highlight\n" +"additions, removals, diff headers, and trailing whitespace.\n" +"\n" +"Other effects in addition to color, like bold and underlined text, are also\n" +"available. Effects are rendered with the ECMA-48 SGR control function (aka\n" +"ANSI escape codes). This module also provides the render_text function,\n" +"which can be used to add effects to any text.\n" +"\n" +"To enable this extension, add this to your .hgrc file:\n" +"[extensions]\n" +"color =\n" +"\n" +"Default effects my be overriden from the .hgrc file:\n" +"\n" +"[color]\n" +"status.modified = blue bold underline red_background\n" +"status.added = green bold\n" +"status.removed = red bold blue_background\n" +"status.deleted = cyan bold underline\n" +"status.unknown = magenta bold underline\n" +"status.ignored = black bold\n" +"\n" +"# 'none' turns off all effects\n" +"status.clean = none\n" +"status.copied = none\n" +"\n" +"qseries.applied = blue bold underline\n" +"qseries.unapplied = black bold\n" +"qseries.missing = red bold\n" +"\n" +"diff.diffline = bold\n" +"diff.extended = cyan bold\n" +"diff.file_a = red bold\n" +"diff.file_b = green bold\n" +"diff.hunk = magenta\n" +"diff.deleted = red\n" +"diff.inserted = green\n" +"diff.changed = white\n" +"diff.trailingwhitespace = bold red_background\n" +msgstr "" + +msgid "Wrap text in commands to turn on each effect." +msgstr "" + +msgid "run the status command with colored output" +msgstr "" + +msgid "run the qseries command with colored output" +msgstr "" + +msgid "wrap ui.write for colored diff output" +msgstr "" + +msgid "wrap cmdutil.changeset_printer.showpatch with colored output" +msgstr "" + +msgid "run the diff command with colored output" +msgstr "" + +msgid "Initialize the extension." +msgstr "" + +msgid "patch in command to command table and load effect map" +msgstr "" + +msgid "when to colorize (always, auto, or never)" +msgstr "" + +msgid "don't colorize output" +msgstr "" + +msgid "converting foreign VCS repositories to Mercurial" +msgstr "" + +msgid "" +"convert a foreign SCM repository to a Mercurial one.\n" +"\n" +" Accepted source formats [identifiers]:\n" +" - Mercurial [hg]\n" +" - CVS [cvs]\n" +" - Darcs [darcs]\n" +" - git [git]\n" +" - Subversion [svn]\n" +" - Monotone [mtn]\n" +" - GNU Arch [gnuarch]\n" +" - Bazaar [bzr]\n" +"\n" +" Accepted destination formats [identifiers]:\n" +" - Mercurial [hg]\n" +" - Subversion [svn] (history on branches is not preserved)\n" +"\n" +" If no revision is given, all revisions will be converted. Otherwise,\n" +" convert will only import up to the named revision (given in a format\n" +" understood by the source).\n" +"\n" +" If no destination directory name is specified, it defaults to the\n" +" basename of the source with '-hg' appended. If the destination\n" +" repository doesn't exist, it will be created.\n" +"\n" +" If isn't given, it will be put in a default location\n" +" (/.hg/shamap by default). The is a simple text\n" +" file that maps each source commit ID to the destination ID for\n" +" that revision, like so:\n" +" \n" +"\n" +" If the file doesn't exist, it's automatically created. It's updated\n" +" on each commit copied, so convert-repo can be interrupted and can\n" +" be run repeatedly to copy new commits.\n" +"\n" +" The [username mapping] file is a simple text file that maps each source\n" +" commit author to a destination commit author. It is handy for source " +"SCMs\n" +" that use unix logins to identify authors (eg: CVS). One line per author\n" +" mapping and the line format is:\n" +" srcauthor=whatever string you want\n" +"\n" +" The filemap is a file that allows filtering and remapping of files\n" +" and directories. Comment lines start with '#'. Each line can\n" +" contain one of the following directives:\n" +"\n" +" include path/to/file\n" +"\n" +" exclude path/to/file\n" +"\n" +" rename from/file to/file\n" +"\n" +" The 'include' directive causes a file, or all files under a\n" +" directory, to be included in the destination repository, and the\n" +" exclusion of all other files and dirs not explicitely included.\n" +" The 'exclude' directive causes files or directories to be omitted.\n" +" The 'rename' directive renames a file or directory. To rename from a\n" +" subdirectory into the root of the repository, use '.' as the path to\n" +" rename to.\n" +"\n" +" The splicemap is a file that allows insertion of synthetic\n" +" history, letting you specify the parents of a revision. This is\n" +" useful if you want to e.g. give a Subversion merge two parents, or\n" +" graft two disconnected series of history together. Each entry\n" +" contains a key, followed by a space, followed by one or two\n" +" values, separated by spaces. The key is the revision ID in the\n" +" source revision control system whose parents should be modified\n" +" (same format as a key in .hg/shamap). The values are the revision\n" +" IDs (in either the source or destination revision control system)\n" +" that should be used as the new parents for that node.\n" +"\n" +" Mercurial Source\n" +" -----------------\n" +"\n" +" --config convert.hg.ignoreerrors=False (boolean)\n" +" ignore integrity errors when reading. Use it to fix Mercurial\n" +" repositories with missing revlogs, by converting from and to\n" +" Mercurial.\n" +" --config convert.hg.saverev=True (boolean)\n" +" allow target to preserve source revision ID\n" +" --config convert.hg.startrev=0 (hg revision identifier)\n" +" convert start revision and its descendants\n" +"\n" +" CVS Source\n" +" ----------\n" +"\n" +" CVS source will use a sandbox (i.e. a checked-out copy) from CVS\n" +" to indicate the starting point of what will be converted. Direct\n" +" access to the repository files is not needed, unless of course\n" +" the repository is :local:. The conversion uses the top level\n" +" directory in the sandbox to find the CVS repository, and then uses\n" +" CVS rlog commands to find files to convert. This means that unless\n" +" a filemap is given, all files under the starting directory will be\n" +" converted, and that any directory reorganisation in the CVS\n" +" sandbox is ignored.\n" +"\n" +" Because CVS does not have changesets, it is necessary to collect\n" +" individual commits to CVS and merge them into changesets. CVS\n" +" source uses its internal changeset merging code by default but can\n" +" be configured to call the external 'cvsps' program by setting:\n" +" --config convert.cvsps='cvsps -A -u --cvs-direct -q'\n" +" This is a legacy option and may be removed in future.\n" +"\n" +" The options shown are the defaults.\n" +"\n" +" Internal cvsps is selected by setting\n" +" --config convert.cvsps=builtin\n" +" and has a few more configurable options:\n" +" --config convert.cvsps.fuzz=60 (integer)\n" +" Specify the maximum time (in seconds) that is allowed between\n" +" commits with identical user and log message in a single\n" +" changeset. When very large files were checked in as part\n" +" of a changeset then the default may not be long enough.\n" +" --config convert.cvsps.mergeto='{{mergetobranch ([-\\w]+)}}'\n" +" Specify a regular expression to which commit log messages are\n" +" matched. If a match occurs, then the conversion process will\n" +" insert a dummy revision merging the branch on which this log\n" +" message occurs to the branch indicated in the regex.\n" +" --config convert.cvsps.mergefrom='{{mergefrombranch ([-\\w]+)}}'\n" +" Specify a regular expression to which commit log messages are\n" +" matched. If a match occurs, then the conversion process will\n" +" add the most recent revision on the branch indicated in the\n" +" regex as the second parent of the changeset.\n" +"\n" +" The hgext/convert/cvsps wrapper script allows the builtin changeset\n" +" merging code to be run without doing a conversion. Its parameters and\n" +" output are similar to that of cvsps 2.1.\n" +"\n" +" Subversion Source\n" +" -----------------\n" +"\n" +" Subversion source detects classical trunk/branches/tags layouts.\n" +" By default, the supplied \"svn://repo/path/\" source URL is\n" +" converted as a single branch. If \"svn://repo/path/trunk\" exists\n" +" it replaces the default branch. If \"svn://repo/path/branches\"\n" +" exists, its subdirectories are listed as possible branches. If\n" +" \"svn://repo/path/tags\" exists, it is looked for tags referencing\n" +" converted branches. Default \"trunk\", \"branches\" and \"tags\" values\n" +" can be overriden with following options. Set them to paths\n" +" relative to the source URL, or leave them blank to disable\n" +" autodetection.\n" +"\n" +" --config convert.svn.branches=branches (directory name)\n" +" specify the directory containing branches\n" +" --config convert.svn.tags=tags (directory name)\n" +" specify the directory containing tags\n" +" --config convert.svn.trunk=trunk (directory name)\n" +" specify the name of the trunk branch\n" +"\n" +" Source history can be retrieved starting at a specific revision,\n" +" instead of being integrally converted. Only single branch\n" +" conversions are supported.\n" +"\n" +" --config convert.svn.startrev=0 (svn revision number)\n" +" specify start Subversion revision.\n" +"\n" +" Mercurial Destination\n" +" ---------------------\n" +"\n" +" --config convert.hg.clonebranches=False (boolean)\n" +" dispatch source branches in separate clones.\n" +" --config convert.hg.tagsbranch=default (branch name)\n" +" tag revisions branch name\n" +" --config convert.hg.usebranchnames=True (boolean)\n" +" preserve branch names\n" +"\n" +" " +msgstr "" + +msgid "" +"create changeset information from CVS\n" +"\n" +" This command is intended as a debugging tool for the CVS to Mercurial\n" +" converter, and can be used as a direct replacement for cvsps.\n" +"\n" +" Hg debugcvsps reads the CVS rlog for current directory (or any named\n" +" directory) in the CVS repository, and converts the log to a series of\n" +" changesets based on matching commit log entries and dates." +msgstr "" + +msgid "username mapping filename" +msgstr "" + +msgid "destination repository type" +msgstr "type for destinations repository" + +msgid "remap file names using contents of file" +msgstr "" + +msgid "import up to target revision REV" +msgstr "" + +msgid "source repository type" +msgstr "" + +msgid "splice synthesized history into place" +msgstr "" + +msgid "try to sort changesets by date" +msgstr "" + +msgid "hg convert [OPTION]... SOURCE [DEST [REVMAP]]" +msgstr "" + +msgid "only return changes on specified branches" +msgstr "" + +msgid "prefix to remove from file names" +msgstr "" + +msgid "only return changes after or between specified tags" +msgstr "" + +msgid "update cvs log cache" +msgstr "" + +msgid "create new cvs log cache" +msgstr "" + +msgid "set commit time fuzz in seconds" +msgstr "" + +msgid "specify cvsroot" +msgstr "" + +msgid "show parent changesets" +msgstr "vis forældre-ændring" + +msgid "show current changeset in ancestor branches" +msgstr "" + +msgid "ignored for compatibility" +msgstr "" + +msgid "hg debugcvsps [OPTION]... [PATH]..." +msgstr "" + +#, python-format +msgid "%s is not a valid revision in current branch" +msgstr "" + +#, python-format +msgid "%s is not available in %s anymore" +msgstr "" + +#, python-format +msgid "cannot find required \"%s\" tool" +msgstr "" + +#, python-format +msgid "running: %s\n" +msgstr "kører: %s\n" + +#, python-format +msgid "%s error:\n" +msgstr "" + +#, python-format +msgid "%s %s" +msgstr "" + +#, python-format +msgid "could not open map file %r: %s" +msgstr "" + +#, python-format +msgid "%s: missing or unsupported repository" +msgstr "" + +#, python-format +msgid "convert: %s\n" +msgstr "" + +#, python-format +msgid "%s: unknown repository type" +msgstr "%s: ukendt arkivtype" + +#, python-format +msgid "cycle detected between %s and %s" +msgstr "" + +msgid "not all revisions were sorted" +msgstr "" + +#, python-format +msgid "Writing author map file %s\n" +msgstr "" + +#, python-format +msgid "Overriding mapping for author %s, was %s, will be %s\n" +msgstr "" + +#, python-format +msgid "mapping author %s to %s\n" +msgstr "" + +#, python-format +msgid "Ignoring bad line in author map file %s: %s\n" +msgstr "" + +#, python-format +msgid "spliced in %s as parents of %s\n" +msgstr "" + +msgid "scanning source...\n" +msgstr "" + +msgid "sorting...\n" +msgstr "" + +msgid "converting...\n" +msgstr "" + +#, python-format +msgid "source: %s\n" +msgstr "" + +#, python-format +msgid "assuming destination %s\n" +msgstr "" + +#, python-format +msgid "revision %s is not a patchset number or date" +msgstr "" + +msgid "using builtin cvsps\n" +msgstr "" + +#, python-format +msgid "connecting to %s\n" +msgstr "" + +msgid "CVS pserver authentication failed" +msgstr "CVS pserver godkendelse fejlede" + +msgid "server sucks" +msgstr "" + +#, python-format +msgid "%d bytes missing from remote file" +msgstr "%d byte mangler i fjernfilen" + +#, python-format +msgid "cvs server: %s\n" +msgstr "cvs server: %s\n" + +#, python-format +msgid "unknown CVS response: %s" +msgstr "ukendt CVS svar: %s" + +msgid "collecting CVS rlog\n" +msgstr "samler CVS rlog\n" + +#, python-format +msgid "reading cvs log cache %s\n" +msgstr "" + +#, python-format +msgid "cache has %d log entries\n" +msgstr "" + +#, python-format +msgid "error reading cache: %r\n" +msgstr "" + +#, python-format +msgid "running %s\n" +msgstr "kører %s\n" + +#, python-format +msgid "prefix=%r directory=%r root=%r\n" +msgstr "" + +msgid "RCS file must be followed by working file" +msgstr "" + +msgid "must have at least some revisions" +msgstr "" + +msgid "expected revision number" +msgstr "" + +msgid "revision must be followed by date line" +msgstr "" + +#, python-format +msgid "writing cvs log cache %s\n" +msgstr "" + +#, python-format +msgid "%d log entries\n" +msgstr "" + +msgid "creating changesets\n" +msgstr "opretter ændringer\n" + +#, python-format +msgid "%d changeset entries\n" +msgstr "%d ændringer\n" + +msgid "Python ElementTree module is not available" +msgstr "" + +#, python-format +msgid "cleaning up %s\n" +msgstr "rydder op %s\n" + +msgid "internal calling inconsistency" +msgstr "" + +msgid "errors in filemap" +msgstr "" + +#, python-format +msgid "%s:%d: %r already in %s list\n" +msgstr "" + +#, python-format +msgid "%s:%d: unknown directive %r\n" +msgstr "" + +msgid "source repository doesn't support --filemap" +msgstr "" + +#, python-format +msgid "%s does not look like a GNU Arch repo" +msgstr "" + +msgid "cannot find a GNU Arch tool" +msgstr "" + +#, python-format +msgid "analyzing tree version %s...\n" +msgstr "" + +#, python-format +msgid "" +"tree analysis stopped because it points to an unregistered archive %s...\n" +msgstr "" + +#, python-format +msgid "applying revision %s...\n" +msgstr "" + +#, python-format +msgid "computing changeset between %s and %s...\n" +msgstr "beregner ændringer mellem %s og %s...\n" + +#, python-format +msgid "obtaining revision %s...\n" +msgstr "henter revision %s...\n" + +#, python-format +msgid "analysing revision %s...\n" +msgstr "analyserer revision %s...\n" + +#, python-format +msgid "could not parse cat-log of %s" +msgstr "" + +#, python-format +msgid "%s is not a local Mercurial repo" +msgstr "" + +#, python-format +msgid "initializing destination %s repository\n" +msgstr "" + +msgid "run hg sink pre-conversion action\n" +msgstr "" + +msgid "run hg sink post-conversion action\n" +msgstr "" + +#, python-format +msgid "pulling from %s into %s\n" +msgstr "" + +msgid "updating tags\n" +msgstr "" + +#, python-format +msgid "%s is not a valid start revision" +msgstr "" + +#, python-format +msgid "ignoring: %s\n" +msgstr "ignorerer: %s\n" + +msgid "run hg source pre-conversion action\n" +msgstr "" + +msgid "run hg source post-conversion action\n" +msgstr "" + +#, python-format +msgid "%s does not look like a monotone repo" +msgstr "" + +#, python-format +msgid "copying file in renamed dir from '%s' to '%s'" +msgstr "" + +msgid "Subversion python bindings could not be loaded" +msgstr "" + +#, python-format +msgid "Subversion python bindings %d.%d found, 1.4 or later required" +msgstr "" + +msgid "Subversion python bindings are too old, 1.4 or later required" +msgstr "" + +#, python-format +msgid "svn: revision %s is not an integer" +msgstr "" + +#, python-format +msgid "svn: start revision %s is not an integer" +msgstr "" + +#, python-format +msgid "no revision found in module %s" +msgstr "" + +#, python-format +msgid "expected %s to be at %r, but not found" +msgstr "" + +#, python-format +msgid "found %s at %r\n" +msgstr "" + +#, python-format +msgid "ignoring empty branch %s\n" +msgstr "" + +#, python-format +msgid "found branch %s at %d\n" +msgstr "" + +msgid "svn: start revision is not supported with with more than one branch" +msgstr "" + +#, python-format +msgid "svn: no revision found after start revision %d" +msgstr "" + +#, python-format +msgid "no tags found at revision %d\n" +msgstr "" + +#, python-format +msgid "ignoring foreign branch %r\n" +msgstr "" + +#, python-format +msgid "%s not found up to revision %d" +msgstr "" + +#, python-format +msgid "branch renamed from %s to %s at %d\n" +msgstr "" + +#, python-format +msgid "reparent to %s\n" +msgstr "" + +#, python-format +msgid "copied to %s from %s@%s\n" +msgstr "" + +#, python-format +msgid "gone from %s\n" +msgstr "" + +#, python-format +msgid "found parent directory %s\n" +msgstr "" + +#, python-format +msgid "base, entry %s %s\n" +msgstr "" + +msgid "munge-o-matic\n" +msgstr "" + +#, python-format +msgid "info: %s %s %s %s\n" +msgstr "" + +#, python-format +msgid "unknown path in revision %d: %s\n" +msgstr "" + +#, python-format +msgid "mark %s came from %s:%d\n" +msgstr "" + +#, python-format +msgid "parsing revision %d (%d changes)\n" +msgstr "" + +#, python-format +msgid "found parent of branch %s at %d: %s\n" +msgstr "" + +msgid "no copyfrom path, don't know what to do.\n" +msgstr "" + +#, python-format +msgid "fetching revision log for \"%s\" from %d to %d\n" +msgstr "" + +#, python-format +msgid "skipping blacklisted revision %d\n" +msgstr "" + +#, python-format +msgid "revision %d has no entries\n" +msgstr "" + +#, python-format +msgid "svn: branch has no revision %s" +msgstr "" + +#, python-format +msgid "%r is not under %r, ignoring\n" +msgstr "" + +#, python-format +msgid "initializing svn repo %r\n" +msgstr "" + +#, python-format +msgid "initializing svn wc %r\n" +msgstr "" + +msgid "unexpected svn output:\n" +msgstr "" + +msgid "unable to cope with svn output" +msgstr "" + +msgid "XXX TAGS NOT IMPLEMENTED YET\n" +msgstr "" + +msgid "" +"\n" +"The `extdiff' Mercurial extension allows you to use external programs\n" +"to compare revisions, or revision with working dir. The external diff\n" +"programs are called with a configurable set of options and two\n" +"non-option arguments: paths to directories containing snapshots of\n" +"files to compare.\n" +"\n" +"To enable this extension:\n" +"\n" +" [extensions]\n" +" hgext.extdiff =\n" +"\n" +"The `extdiff' extension also allows to configure new diff commands, so\n" +"you do not need to type \"hg extdiff -p kdiff3\" always.\n" +"\n" +" [extdiff]\n" +" # add new command that runs GNU diff(1) in 'context diff' mode\n" +" cdiff = gdiff -Nprc5\n" +" ## or the old way:\n" +" #cmd.cdiff = gdiff\n" +" #opts.cdiff = -Nprc5\n" +"\n" +" # add new command called vdiff, runs kdiff3\n" +" vdiff = kdiff3\n" +"\n" +" # add new command called meld, runs meld (no need to name twice)\n" +" meld =\n" +"\n" +" # add new command called vimdiff, runs gvimdiff with DirDiff plugin\n" +" #(see http://www.vim.org/scripts/script.php?script_id=102)\n" +" # Non english user, be sure to put \"let g:DirDiffDynamicDiffText = 1\" " +"in\n" +" # your .vimrc\n" +" vimdiff = gvim -f '+next' '+execute \"DirDiff\" argv(0) argv(1)'\n" +"\n" +"You can use -I/-X and list of file or directory names like normal\n" +"\"hg diff\" command. The `extdiff' extension makes snapshots of only\n" +"needed files, so running the external diff program will actually be\n" +"pretty fast (at least faster than having to compare the entire tree).\n" +msgstr "" + +msgid "snapshot files as of some revision" +msgstr "" + +#, python-format +msgid "making snapshot of %d files from rev %s\n" +msgstr "" + +msgid "" +"snapshot files from working directory.\n" +" if not using snapshot, -I/-X does not work and recursive diff\n" +" in tools like kdiff3 and meld displays too many files." +msgstr "" + +#, python-format +msgid "making snapshot of %d files from working dir\n" +msgstr "" + +msgid "" +"Do the actuall diff:\n" +"\n" +" - copy to a temp structure if diffing 2 internal revisions\n" +" - copy to a temp structure if diffing working revision with\n" +" another one and more than 1 file is changed\n" +" - just invoke the diff for a single file in the working dir\n" +" " +msgstr "" + +msgid "cannot specify --rev and --change at the same time" +msgstr "" + +#, python-format +msgid "running %r in %s\n" +msgstr "" + +#, python-format +msgid "file changed while diffing. Overwriting: %s (src: %s)\n" +msgstr "" + +msgid "cleaning up temp directory\n" +msgstr "" + +msgid "" +"use external program to diff repository (or selected files)\n" +"\n" +" Show differences between revisions for the specified files, using\n" +" an external program. The default program used is diff, with\n" +" default options \"-Npru\".\n" +"\n" +" To select a different program, use the -p option. The program\n" +" will be passed the names of two directories to compare. To pass\n" +" additional options to the program, use the -o option. These will\n" +" be passed before the names of the directories to compare.\n" +"\n" +" When two revision arguments are given, then changes are\n" +" shown between those revisions. If only one revision is\n" +" specified then that revision is compared to the working\n" +" directory, and, when no revisions are specified, the\n" +" working directory files are compared to its parent." +msgstr "" + +msgid "comparison program to run" +msgstr "" + +msgid "pass option to comparison program" +msgstr "" + +msgid "change made by revision" +msgstr "" + +msgid "hg extdiff [OPT]... [FILE]..." +msgstr "" + +msgid "use closure to save diff command to use" +msgstr "" + +#, python-format +msgid "hg %s [OPTION]... [FILE]..." +msgstr "" + +msgid "pulling, updating and merging in one command" +msgstr "" + +msgid "" +"pull changes from a remote repository, merge new changes if needed.\n" +"\n" +" This finds all changes from the repository at the specified path\n" +" or URL and adds them to the local repository.\n" +"\n" +" If the pulled changes add a new branch head, the head is automatically\n" +" merged, and the result of the merge is committed. Otherwise, the\n" +" working directory is updated to include the new changes.\n" +"\n" +" When a merge occurs, the newly pulled changes are assumed to be\n" +" \"authoritative\". The head of the new changes is used as the first\n" +" parent, with local changes as the second. To switch the merge\n" +" order, use --switch-parent.\n" +"\n" +" See 'hg help dates' for a list of formats valid for -d/--date.\n" +" " +msgstr "" + +msgid "" +"working dir not at branch tip (use \"hg update\" to check out branch tip)" +msgstr "" + +msgid "outstanding uncommitted merge" +msgstr "" + +msgid "outstanding uncommitted changes" +msgstr "" + +msgid "working directory is missing some files" +msgstr "arbejdsbiblioteket mangler nogle filer" + +msgid "" +"multiple heads in this branch (use \"hg heads .\" and \"hg merge\" to merge)" +msgstr "" + +#, python-format +msgid "pulling from %s\n" +msgstr "hiver fra %s\n" + +msgid "fetch -r doesn't work for remote repositories yet" +msgstr "fetch -r virker endnu ikke for fjernarkiver" + +#, python-format +msgid "" +"not merging with %d other new branch heads (use \"hg heads .\" and \"hg merge" +"\" to merge them)\n" +msgstr "" + +#, python-format +msgid "updating to %d:%s\n" +msgstr "opdaterer til %d:%s\n" + +#, python-format +msgid "merging with %d:%s\n" +msgstr "sammenføjer med %d:%s\n" + +#, python-format +msgid "Automated merge with %s" +msgstr "" + +#, python-format +msgid "new changeset %d:%s merges remote changes with local\n" +msgstr "ny ændring %d:%s fletter fjernændringer sammen med lokale\n" + +msgid "a specific revision you would like to pull" +msgstr "" + +msgid "edit commit message" +msgstr "" + +msgid "edit commit message (DEPRECATED)" +msgstr "" + +msgid "switch parents when merging" +msgstr "" + +msgid "hg fetch [SOURCE]" +msgstr "" + +msgid " returns of the good and bad signatures" +msgstr "" + +msgid "error while verifying signature" +msgstr "" + +msgid "create a new gpg instance" +msgstr "" + +msgid "" +"\n" +" walk over every sigs, yields a couple\n" +" ((node, version, sig), (filename, linenumber))\n" +" " +msgstr "" + +msgid "get the keys who signed a data" +msgstr "" + +#, python-format +msgid "%s Bad signature from \"%s\"\n" +msgstr "" + +#, python-format +msgid "%s Note: Signature has expired (signed by: \"%s\")\n" +msgstr "" + +#, python-format +msgid "%s Note: This key has expired (signed by: \"%s\")\n" +msgstr "" + +msgid "list signed changesets" +msgstr "vis underskrevne ændringer" + +#, python-format +msgid "%s:%d node does not exist\n" +msgstr "%s:%d knude findes ikke\n" + +msgid "verify all the signatures there may be for a particular revision" +msgstr "verificer alle underskrifter der måtte være for en given revision" + +#, python-format +msgid "No valid signature for %s\n" +msgstr "Ingen gyldig signatur for %s\n" + +msgid "associate a string to a key (username, comment)" +msgstr "" + +msgid "" +"add a signature for the current or given revision\n" +"\n" +" If no revision is given, the parent of the working directory is used,\n" +" or tip if no revision is checked out.\n" +"\n" +" See 'hg help dates' for a list of formats valid for -d/--date.\n" +" " +msgstr "" + +msgid "uncommitted merge - please provide a specific revision" +msgstr "" + +msgid "Error while signing" +msgstr "Fejl ved underskrivning" + +msgid "" +"working copy of .hgsigs is changed (please commit .hgsigs manually or use --" +"force)" +msgstr "" + +#, python-format +msgid "Added signature for changeset %s" +msgstr "" + +msgid "map a manifest into some text" +msgstr "" + +msgid "unknown signature version" +msgstr "" + +msgid "make the signature local" +msgstr "" + +msgid "sign even if the sigfile is modified" +msgstr "" + +msgid "do not commit the sigfile after signing" +msgstr "" + +msgid "the key id to sign with" +msgstr "" + +msgid "commit message" +msgstr "" + +msgid "hg sign [OPTION]... [REVISION]..." +msgstr "" + +msgid "hg sigcheck REVISION" +msgstr "" + +msgid "hg sigs" +msgstr "" + +msgid "" +"show revision graphs in terminal windows\n" +"\n" +"This extension adds a --graph option to the incoming, outgoing and log\n" +"commands. When this options is given, an ascii representation of the\n" +"revision graph is also shown.\n" +msgstr "" + +msgid "" +"cset DAG generator yielding (rev, node, [parents]) tuples\n" +"\n" +" This generator function walks through the revision history from " +"revision\n" +" start to revision stop (which must be less than or equal to start).\n" +" " +msgstr "" + +msgid "" +"file cset DAG generator yielding (rev, node, [parents]) tuples\n" +"\n" +" This generator function walks through the revision history of a single\n" +" file from revision start to revision stop (which must be less than or\n" +" equal to start).\n" +" " +msgstr "" + +msgid "" +"grapher for asciigraph on a list of nodes and their parents\n" +"\n" +" nodes must generate tuples (node, parents, char, lines) where\n" +" - parents must generate the parents of node, in sorted order,\n" +" and max length 2,\n" +" - char is the char to print as the node symbol, and\n" +" - lines are the lines to display next to the node.\n" +" " +msgstr "" + +msgid "" +"prints an ASCII graph of the DAG returned by the grapher\n" +"\n" +" grapher is a generator that emits tuples with the following elements:\n" +"\n" +" - Character to use as node's symbol.\n" +" - List of lines to display as the node's text.\n" +" - Column of the current node in the set of ongoing edges.\n" +" - Edges; a list of (col, next_col) indicating the edges between\n" +" the current node and its parents.\n" +" - Number of columns (ongoing edges) in the current revision.\n" +" - The difference between the number of columns (ongoing edges)\n" +" in the next revision and the number of columns (ongoing edges)\n" +" in the current revision. That is: -1 means one column removed;\n" +" 0 means no columns added or removed; 1 means one column added.\n" +" " +msgstr "" + +#, python-format +msgid "--graph option is incompatible with --%s" +msgstr "" + +msgid "" +"show revision history alongside an ASCII revision graph\n" +"\n" +" Print a revision history alongside a revision graph drawn with\n" +" ASCII characters.\n" +"\n" +" Nodes printed as an @ character are parents of the working\n" +" directory.\n" +" " +msgstr "" + +msgid "" +"show the outgoing changesets alongside an ASCII revision graph\n" +"\n" +" Print the outgoing changesets alongside a revision graph drawn with\n" +" ASCII characters.\n" +"\n" +" Nodes printed as an @ character are parents of the working\n" +" directory.\n" +" " +msgstr "" + +#, python-format +msgid "comparing with %s\n" +msgstr "sammenligner med %s\n" + +msgid "no changes found\n" +msgstr "fandt ingen ændringer\n" + +msgid "" +"show the incoming changesets alongside an ASCII revision graph\n" +"\n" +" Print the incoming changesets alongside a revision graph drawn with\n" +" ASCII characters.\n" +"\n" +" Nodes printed as an @ character are parents of the working\n" +" directory.\n" +" " +msgstr "" + +msgid "wrap the command" +msgstr "" + +msgid "show the revision DAG" +msgstr "" + +msgid "limit number of changes displayed" +msgstr "" + +msgid "show patch" +msgstr "" + +msgid "show the specified revision or range" +msgstr "" + +msgid "hg glog [OPTION]... [FILE]" +msgstr "" + +msgid "" +"CIA notification\n" +"\n" +"This is meant to be run as a changegroup or incoming hook.\n" +"To configure it, set the following options in your hgrc:\n" +"\n" +"[cia]\n" +"# your registered CIA user name\n" +"user = foo\n" +"# the name of the project in CIA\n" +"project = foo\n" +"# the module (subproject) (optional)\n" +"#module = foo\n" +"# Append a diffstat to the log message (optional)\n" +"#diffstat = False\n" +"# Template to use for log messages (optional)\n" +"#template = {desc}\n" +"{baseurl}/rev/{node}-- {diffstat}\n" +"# Style to use (optional)\n" +"#style = foo\n" +"# The URL of the CIA notification service (optional)\n" +"# You can use mailto: URLs to send by email, eg\n" +"# mailto:cia@cia.vc\n" +"# Make sure to set email.from if you do this.\n" +"#url = http://cia.vc/\n" +"# print message instead of sending it (optional)\n" +"#test = False\n" +"\n" +"[hooks]\n" +"# one of these:\n" +"changegroup.cia = python:hgcia.hook\n" +"#incoming.cia = python:hgcia.hook\n" +"\n" +"[web]\n" +"# If you want hyperlinks (optional)\n" +"baseurl = http://server/path/to/repo\n" +msgstr "" + +msgid " A CIA message " +msgstr "" + +msgid " CIA notification class " +msgstr "" + +#, python-format +msgid "hgcia: sending update to %s\n" +msgstr "" + +msgid " send CIA notification " +msgstr "" + +msgid "email.from must be defined when sending by email" +msgstr "" + +msgid "cia: no user specified" +msgstr "cia: ingen bruger angivet" + +msgid "cia: no project specified" +msgstr "cia: intet project angivet" + +msgid "" +"browsing the repository in a graphical way\n" +"\n" +"The hgk extension allows browsing the history of a repository in a\n" +"graphical way. It requires Tcl/Tk version 8.4 or later. (Tcl/Tk is\n" +"not distributed with Mercurial.)\n" +"\n" +"hgk consists of two parts: a Tcl script that does the displaying and\n" +"querying of information, and an extension to mercurial named hgk.py,\n" +"which provides hooks for hgk to get information. hgk can be found in\n" +"the contrib directory, and hgk.py can be found in the hgext directory.\n" +"\n" +"To load the hgext.py extension, add it to your .hgrc file (you have\n" +"to use your global $HOME/.hgrc file, not one in a repository). You\n" +"can specify an absolute path:\n" +"\n" +" [extensions]\n" +" hgk=/usr/local/lib/hgk.py\n" +"\n" +"Mercurial can also scan the default python library path for a file\n" +"named 'hgk.py' if you set hgk empty:\n" +"\n" +" [extensions]\n" +" hgk=\n" +"\n" +"The hg view command will launch the hgk Tcl script. For this command\n" +"to work, hgk must be in your search path. Alternately, you can\n" +"specify the path to hgk in your .hgrc file:\n" +"\n" +" [hgk]\n" +" path=/location/of/hgk\n" +"\n" +"hgk can make use of the extdiff extension to visualize revisions.\n" +"Assuming you had already configured extdiff vdiff command, just add:\n" +"\n" +" [hgk]\n" +" vdiff=vdiff\n" +"\n" +"Revisions context menu will now display additional entries to fire\n" +"vdiff on hovered and selected revisions." +msgstr "" + +msgid "diff trees from two commits" +msgstr "" + +msgid "output common ancestor information" +msgstr "" + +msgid "cat a specific revision" +msgstr "" + +msgid "cat-file: type or revision not supplied\n" +msgstr "" + +msgid "aborting hg cat-file only understands commits\n" +msgstr "" + +msgid "parse given revisions" +msgstr "" + +msgid "print revisions" +msgstr "" + +msgid "print extension options" +msgstr "" + +msgid "start interactive history viewer" +msgstr "" + +msgid "hg view [-l LIMIT] [REVRANGE]" +msgstr "" + +msgid "generate patch" +msgstr "" + +msgid "recursive" +msgstr "" + +msgid "pretty" +msgstr "" + +msgid "stdin" +msgstr "" + +msgid "detect copies" +msgstr "" + +msgid "search" +msgstr "søg" + +msgid "hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]..." +msgstr "" + +msgid "hg debug-cat-file [OPTION]... TYPE FILE" +msgstr "" + +msgid "hg debug-config" +msgstr "" + +msgid "hg debug-merge-base node node" +msgstr "" + +msgid "ignored" +msgstr "Ignoreret" + +msgid "hg debug-rev-parse REV" +msgstr "" + +msgid "header" +msgstr "" + +msgid "topo-order" +msgstr "" + +msgid "parents" +msgstr "" + +msgid "max-count" +msgstr "" + +msgid "hg debug-rev-list [options] revs" +msgstr "" + +msgid "" +"syntax highlighting in hgweb, based on Pygments\n" +"\n" +"It depends on the pygments syntax highlighting library:\n" +"http://pygments.org/\n" +"\n" +"To enable the extension add this to hgrc:\n" +"\n" +"[extensions]\n" +"hgext.highlight =\n" +"\n" +"There is a single configuration option:\n" +"\n" +"[web]\n" +"pygments_style =