# HG changeset patch # User Thomas Arendsen Hein # Date 1203358893 -3600 # Node ID 50a277e6ceaeaa5f890cacc9dcab745a4387dd58 # Parent 90e5c82a3859f1c287d89e729deb3b8436d85ed5# Parent 47e6d5d5913a9a4487e07ca2bc188b2b0e3744ce merge backout diff -r 90e5c82a3859 -r 50a277e6ceae contrib/favicon.ico Binary file contrib/favicon.ico has changed diff -r 90e5c82a3859 -r 50a277e6ceae contrib/hgwebdir.fcgi --- a/contrib/hgwebdir.fcgi Mon Feb 18 19:20:22 2008 +0100 +++ b/contrib/hgwebdir.fcgi Mon Feb 18 19:21:33 2008 +0100 @@ -9,9 +9,9 @@ # enable demandloading to reduce startup time from mercurial import demandimport; demandimport.enable() -# send python tracebacks to the browser if an error occurs: -import cgitb -cgitb.enable() +# Uncomment to send python tracebacks to the browser if an error occurs: +#import cgitb +#cgitb.enable() # 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. diff -r 90e5c82a3859 -r 50a277e6ceae contrib/logo-droplets.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/logo-droplets.svg Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,624 @@ + + +image/svg+xmlMercurial "droplets" logoCali Mastny and Matt MackallFeb 12 2008 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -r 90e5c82a3859 -r 50a277e6ceae contrib/mergetools.hgrc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/mergetools.hgrc Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,50 @@ +# Some default global settings for common merge tools + +[merge-tools] +kdiff3.args=--auto -L1 base --L2 local --L3 other $base $local $other -o $output +kdiff3.regkey=Software\KDiff3 +kdiff3.regappend=\kdiff3.exe +kdiff3.fixeol=True +kdiff3.gui=True + +gvimdiff.args=--nofork -d -g -O $local $other $base +gvimdiff.regkey=Software\Vim\GVim +gvimdiff.regname=path +gvimdiff.priority=-9 + +merge.checkconflicts=True +merge.priority=-10 + +gpyfm.gui=True + +meld.gui=True + +tkdiff.args=$local $other -a $base -o $output +tkdiff.gui=True +tkdiff.priority=-8 + +xxdiff.args=--show-merged-pane --exit-with-merge-status --title1 local --title2 base --title3 other --merged-filename $output --merge $local $base $other +xxdiff.gui=True +xxdiff.priority=-8 + +diffmerge.args=--nosplash --merge --title1=base --title2=local --title3=other $base $local $other +diffmerge.checkchanged=True +diffmerge.gui=True + +p4merge.args=$base $local $other $output +p4merge.regkey=Software\Perforce\Environment +p4merge.regname=P4INSTROOT +p4merge.regappend=\p4merge.exe +p4merge.gui=True +p4merge.priority=-8 + +tortoisemerge.args=/base: $output /mine:$local /theirs:$other /merged:$output +tortoisemerge.regkey=Software\TortoiseSVN +tortoisemerge.gui=True + +ecmerge.args=$base $local $other --mode=merge3 --title0=base --title1=local --title2=other --to=$output +ecmerge.regkey=Software\Elli\xc3\xa9 Computing\Merge +ecmerge.gui=True + +filemerge.args=-left $other -right $local -ancestor $base -merge $output +filemerge.gui=True diff -r 90e5c82a3859 -r 50a277e6ceae contrib/simplemerge --- a/contrib/simplemerge Mon Feb 18 19:20:22 2008 +0100 +++ b/contrib/simplemerge Mon Feb 18 19:21:33 2008 +0100 @@ -1,503 +1,11 @@ #!/usr/bin/env python -# Copyright (C) 2004, 2005 Canonical Ltd -# -# This program 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. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -# mbp: "you know that thing where cvs gives you conflict markers?" -# s: "i hate that." from mercurial import demandimport demandimport.enable() -from mercurial import util, mdiff, fancyopts +import os, sys from mercurial.i18n import _ - - -class CantReprocessAndShowBase(Exception): - pass - - -def warn(message): - sys.stdout.flush() - sys.stderr.write(message) - sys.stderr.flush() - - -def intersect(ra, rb): - """Given two ranges return the range where they intersect or None. - - >>> intersect((0, 10), (0, 6)) - (0, 6) - >>> intersect((0, 10), (5, 15)) - (5, 10) - >>> intersect((0, 10), (10, 15)) - >>> intersect((0, 9), (10, 15)) - >>> intersect((0, 9), (7, 15)) - (7, 9) - """ - assert ra[0] <= ra[1] - assert rb[0] <= rb[1] - - sa = max(ra[0], rb[0]) - sb = min(ra[1], rb[1]) - if sa < sb: - return sa, sb - else: - return None - - -def compare_range(a, astart, aend, b, bstart, bend): - """Compare a[astart:aend] == b[bstart:bend], without slicing. - """ - if (aend-astart) != (bend-bstart): - return False - for ia, ib in zip(xrange(astart, aend), xrange(bstart, bend)): - if a[ia] != b[ib]: - return False - else: - return True - - - - -class Merge3Text(object): - """3-way merge of texts. - - Given strings BASE, OTHER, THIS, tries to produce a combined text - incorporating the changes from both BASE->OTHER and BASE->THIS.""" - def __init__(self, basetext, atext, btext, base=None, a=None, b=None): - self.basetext = basetext - self.atext = atext - self.btext = btext - if base is None: - base = mdiff.splitnewlines(basetext) - if a is None: - a = mdiff.splitnewlines(atext) - if b is None: - b = mdiff.splitnewlines(btext) - self.base = base - self.a = a - self.b = b - - - - def merge_lines(self, - name_a=None, - name_b=None, - name_base=None, - start_marker='<<<<<<<', - mid_marker='=======', - end_marker='>>>>>>>', - base_marker=None, - reprocess=False): - """Return merge in cvs-like form. - """ - self.conflicts = False - newline = '\n' - if len(self.a) > 0: - if self.a[0].endswith('\r\n'): - newline = '\r\n' - elif self.a[0].endswith('\r'): - newline = '\r' - if base_marker and reprocess: - raise CantReprocessAndShowBase() - if name_a: - start_marker = start_marker + ' ' + name_a - if name_b: - end_marker = end_marker + ' ' + name_b - if name_base and base_marker: - base_marker = base_marker + ' ' + name_base - merge_regions = self.merge_regions() - if reprocess is True: - merge_regions = self.reprocess_merge_regions(merge_regions) - for t in merge_regions: - what = t[0] - if what == 'unchanged': - for i in range(t[1], t[2]): - yield self.base[i] - elif what == 'a' or what == 'same': - for i in range(t[1], t[2]): - yield self.a[i] - elif what == 'b': - for i in range(t[1], t[2]): - yield self.b[i] - elif what == 'conflict': - self.conflicts = True - yield start_marker + newline - for i in range(t[3], t[4]): - yield self.a[i] - if base_marker is not None: - yield base_marker + newline - for i in range(t[1], t[2]): - yield self.base[i] - yield mid_marker + newline - for i in range(t[5], t[6]): - yield self.b[i] - yield end_marker + newline - else: - raise ValueError(what) - - - - - - def merge_annotated(self): - """Return merge with conflicts, showing origin of lines. - - Most useful for debugging merge. - """ - for t in self.merge_regions(): - what = t[0] - if what == 'unchanged': - for i in range(t[1], t[2]): - yield 'u | ' + self.base[i] - elif what == 'a' or what == 'same': - for i in range(t[1], t[2]): - yield what[0] + ' | ' + self.a[i] - elif what == 'b': - for i in range(t[1], t[2]): - yield 'b | ' + self.b[i] - elif what == 'conflict': - yield '<<<<\n' - for i in range(t[3], t[4]): - yield 'A | ' + self.a[i] - yield '----\n' - for i in range(t[5], t[6]): - yield 'B | ' + self.b[i] - yield '>>>>\n' - else: - raise ValueError(what) - - - - - - def merge_groups(self): - """Yield sequence of line groups. Each one is a tuple: - - 'unchanged', lines - Lines unchanged from base - - 'a', lines - Lines taken from a - - 'same', lines - Lines taken from a (and equal to b) - - 'b', lines - Lines taken from b - - 'conflict', base_lines, a_lines, b_lines - Lines from base were changed to either a or b and conflict. - """ - for t in self.merge_regions(): - what = t[0] - if what == 'unchanged': - yield what, self.base[t[1]:t[2]] - elif what == 'a' or what == 'same': - yield what, self.a[t[1]:t[2]] - elif what == 'b': - yield what, self.b[t[1]:t[2]] - elif what == 'conflict': - yield (what, - self.base[t[1]:t[2]], - self.a[t[3]:t[4]], - self.b[t[5]:t[6]]) - else: - raise ValueError(what) - - - def merge_regions(self): - """Return sequences of matching and conflicting regions. - - This returns tuples, where the first value says what kind we - have: - - 'unchanged', start, end - Take a region of base[start:end] - - 'same', astart, aend - b and a are different from base but give the same result - - 'a', start, end - Non-clashing insertion from a[start:end] - - Method is as follows: - - The two sequences align only on regions which match the base - and both descendents. These are found by doing a two-way diff - of each one against the base, and then finding the - intersections between those regions. These "sync regions" - are by definition unchanged in both and easily dealt with. - - The regions in between can be in any of three cases: - conflicted, or changed on only one side. - """ - - # section a[0:ia] has been disposed of, etc - iz = ia = ib = 0 - - for zmatch, zend, amatch, aend, bmatch, bend in self.find_sync_regions(): - #print 'match base [%d:%d]' % (zmatch, zend) - - matchlen = zend - zmatch - assert matchlen >= 0 - assert matchlen == (aend - amatch) - assert matchlen == (bend - bmatch) - - len_a = amatch - ia - len_b = bmatch - ib - len_base = zmatch - iz - assert len_a >= 0 - assert len_b >= 0 - assert len_base >= 0 - - #print 'unmatched a=%d, b=%d' % (len_a, len_b) - - if len_a or len_b: - # try to avoid actually slicing the lists - equal_a = compare_range(self.a, ia, amatch, - self.base, iz, zmatch) - equal_b = compare_range(self.b, ib, bmatch, - self.base, iz, zmatch) - same = compare_range(self.a, ia, amatch, - self.b, ib, bmatch) - - if same: - yield 'same', ia, amatch - elif equal_a and not equal_b: - yield 'b', ib, bmatch - elif equal_b and not equal_a: - yield 'a', ia, amatch - elif not equal_a and not equal_b: - yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch - else: - raise AssertionError("can't handle a=b=base but unmatched") - - ia = amatch - ib = bmatch - iz = zmatch - - # if the same part of the base was deleted on both sides - # that's OK, we can just skip it. - - - if matchlen > 0: - assert ia == amatch - assert ib == bmatch - assert iz == zmatch - - yield 'unchanged', zmatch, zend - iz = zend - ia = aend - ib = bend - - - def reprocess_merge_regions(self, merge_regions): - """Where there are conflict regions, remove the agreed lines. - - Lines where both A and B have made the same changes are - eliminated. - """ - for region in merge_regions: - if region[0] != "conflict": - yield region - continue - type, iz, zmatch, ia, amatch, ib, bmatch = region - a_region = self.a[ia:amatch] - b_region = self.b[ib:bmatch] - matches = mdiff.get_matching_blocks(''.join(a_region), - ''.join(b_region)) - next_a = ia - next_b = ib - for region_ia, region_ib, region_len in matches[:-1]: - region_ia += ia - region_ib += ib - reg = self.mismatch_region(next_a, region_ia, next_b, - region_ib) - if reg is not None: - yield reg - yield 'same', region_ia, region_len+region_ia - next_a = region_ia + region_len - next_b = region_ib + region_len - reg = self.mismatch_region(next_a, amatch, next_b, bmatch) - if reg is not None: - yield reg - - - def mismatch_region(next_a, region_ia, next_b, region_ib): - if next_a < region_ia or next_b < region_ib: - return 'conflict', None, None, next_a, region_ia, next_b, region_ib - mismatch_region = staticmethod(mismatch_region) - - - def find_sync_regions(self): - """Return a list of sync regions, where both descendents match the base. - - Generates a list of (base1, base2, a1, a2, b1, b2). There is - always a zero-length sync region at the end of all the files. - """ - - ia = ib = 0 - amatches = mdiff.get_matching_blocks(self.basetext, self.atext) - bmatches = mdiff.get_matching_blocks(self.basetext, self.btext) - len_a = len(amatches) - len_b = len(bmatches) - - sl = [] - - while ia < len_a and ib < len_b: - abase, amatch, alen = amatches[ia] - bbase, bmatch, blen = bmatches[ib] - - # there is an unconflicted block at i; how long does it - # extend? until whichever one ends earlier. - i = intersect((abase, abase+alen), (bbase, bbase+blen)) - if i: - intbase = i[0] - intend = i[1] - intlen = intend - intbase - - # found a match of base[i[0], i[1]]; this may be less than - # the region that matches in either one - assert intlen <= alen - assert intlen <= blen - assert abase <= intbase - assert bbase <= intbase - - asub = amatch + (intbase - abase) - bsub = bmatch + (intbase - bbase) - aend = asub + intlen - bend = bsub + intlen - - assert self.base[intbase:intend] == self.a[asub:aend], \ - (self.base[intbase:intend], self.a[asub:aend]) - - assert self.base[intbase:intend] == self.b[bsub:bend] - - sl.append((intbase, intend, - asub, aend, - bsub, bend)) - - # advance whichever one ends first in the base text - if (abase + alen) < (bbase + blen): - ia += 1 - else: - ib += 1 - - intbase = len(self.base) - abase = len(self.a) - bbase = len(self.b) - sl.append((intbase, intbase, abase, abase, bbase, bbase)) - - return sl - - - - def find_unconflicted(self): - """Return a list of ranges in base that are not conflicted.""" - am = mdiff.get_matching_blocks(self.basetext, self.atext) - bm = mdiff.get_matching_blocks(self.basetext, self.btext) - - unc = [] - - while am and bm: - # there is an unconflicted block at i; how long does it - # extend? until whichever one ends earlier. - a1 = am[0][0] - a2 = a1 + am[0][2] - b1 = bm[0][0] - b2 = b1 + bm[0][2] - i = intersect((a1, a2), (b1, b2)) - if i: - unc.append(i) - - if a2 < b2: - del am[0] - else: - del bm[0] - - return unc - - -# bzr compatible interface, for the tests -class Merge3(Merge3Text): - """3-way merge of texts. - - Given BASE, OTHER, THIS, tries to produce a combined text - incorporating the changes from both BASE->OTHER and BASE->THIS. - All three will typically be sequences of lines.""" - def __init__(self, base, a, b): - basetext = '\n'.join([i.strip('\n') for i in base] + ['']) - atext = '\n'.join([i.strip('\n') for i in a] + ['']) - btext = '\n'.join([i.strip('\n') for i in b] + ['']) - if util.binary(basetext) or util.binary(atext) or util.binary(btext): - raise util.Abort(_("don't know how to merge binary files")) - Merge3Text.__init__(self, basetext, atext, btext, base, a, b) - - -def simplemerge(local, base, other, **opts): - def readfile(filename): - f = open(filename, "rb") - text = f.read() - f.close() - if util.binary(text): - msg = _("%s looks like a binary file.") % filename - if not opts.get('text'): - raise util.Abort(msg) - elif not opts.get('quiet'): - warn(_('warning: %s\n') % msg) - return text - - name_a = local - name_b = other - labels = opts.get('label', []) - if labels: - name_a = labels.pop(0) - if labels: - name_b = labels.pop(0) - if labels: - raise util.Abort(_("can only specify two labels.")) - - localtext = readfile(local) - basetext = readfile(base) - othertext = readfile(other) - - orig = local - local = os.path.realpath(local) - if not opts.get('print'): - opener = util.opener(os.path.dirname(local)) - out = opener(os.path.basename(local), "w", atomictemp=True) - else: - out = sys.stdout - - reprocess = not opts.get('no_minimal') - - m3 = Merge3Text(basetext, localtext, othertext) - for line in m3.merge_lines(name_a=name_a, name_b=name_b, - reprocess=reprocess): - out.write(line) - - if not opts.get('print'): - out.rename() - - if m3.conflicts: - if not opts.get('quiet'): - warn(_("warning: conflicts during merge.\n")) - return 1 +from mercurial import simplemerge, fancyopts, util options = [('L', 'label', [], _('labels to use on conflict markers')), ('a', 'text', None, _('treat all files as text')), @@ -517,6 +25,9 @@ By default, LOCAL is overwritten with the results of this operation. ''') +class ParseError(Exception): + """Exception raised on errors in parsing the command line.""" + def showhelp(): sys.stdout.write(usage) sys.stdout.write('\noptions:\n') @@ -530,33 +41,24 @@ for first, second in out_opts: sys.stdout.write(' %-*s %s\n' % (opts_len, first, second)) -class ParseError(Exception): - """Exception raised on errors in parsing the command line.""" - -def main(argv): +try: + opts = {} try: - opts = {} - try: - args = fancyopts.fancyopts(argv[1:], options, opts) - except fancyopts.getopt.GetoptError, e: - raise ParseError(e) - if opts['help']: - showhelp() - return 0 - if len(args) != 3: - raise ParseError(_('wrong number of arguments')) - return simplemerge(*args, **opts) - except ParseError, e: - sys.stdout.write("%s: %s\n" % (sys.argv[0], e)) + args = fancyopts.fancyopts(sys.argv[1:], options, opts) + except fancyopts.getopt.GetoptError, e: + raise ParseError(e) + if opts['help']: showhelp() - return 1 - except util.Abort, e: - sys.stderr.write("abort: %s\n" % e) - return 255 - except KeyboardInterrupt: - return 255 - -if __name__ == '__main__': - import sys - import os - sys.exit(main(sys.argv)) + sys.exit(0) + if len(args) != 3: + raise ParseError(_('wrong number of arguments')) + sys.exit(simplemerge.simplemerge(*args, **opts)) +except ParseError, e: + sys.stdout.write("%s: %s\n" % (sys.argv[0], e)) + showhelp() + sys.exit(1) +except util.Abort, e: + sys.stderr.write("abort: %s\n" % e) + sys.exit(255) +except KeyboardInterrupt: + sys.exit(255) diff -r 90e5c82a3859 -r 50a277e6ceae doc/hgmerge.1.txt --- a/doc/hgmerge.1.txt Mon Feb 18 19:20:22 2008 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -HGMERGE(1) -========== -Matt Mackall -v0.1, 27 May 2005 - -NAME ----- -hgmerge - default wrapper to merge files in Mercurial SCM system - -SYNOPSIS --------- -'hgmerge' local ancestor remote - -DESCRIPTION ------------ -The hgmerge(1) command provides a graphical interface to merge files in the -Mercurial system. It is a simple wrapper around kdiff3, merge(1) and tkdiff(1), -or simply diff(1) and patch(1) depending on what is present on the system. - -hgmerge(1) is used by the Mercurial SCM if the environment variable HGMERGE is -not set. - -AUTHOR ------- -Written by Vincent Danjean - -SEE ALSO --------- -hg(1) - the command line interface to Mercurial SCM - -COPYING -------- -Copyright \(C) 2005-2007 Matt Mackall. -Free use of this software is granted under the terms of the GNU General -Public License (GPL). diff -r 90e5c82a3859 -r 50a277e6ceae doc/hgrc.5.txt --- a/doc/hgrc.5.txt Mon Feb 18 19:20:22 2008 +0100 +++ b/doc/hgrc.5.txt Mon Feb 18 19:21:33 2008 +0100 @@ -233,6 +233,82 @@ you to store longer filenames in some situations at the expense of compatibility. +merge-patterns:: + This section specifies merge tools to associate with particular file + patterns. Tools matched here will take precedence over the default + merge tool. Patterns are globs by default, rooted at the repository root. + + Example: + + [merge-patterns] + **.c = kdiff3 + **.jpg = myimgmerge + +merge-tools:: + This section configures external merge tools to use for file-level + merges. + + Example ~/.hgrc: + + [merge-tools] + # Override stock tool location + kdiff3.executable = ~/bin/kdiff3 + # Specify command line + kdiff3.args = $base $local $other -o $output + # Give higher priority + kdiff3.priority = 1 + + # Define new tool + myHtmlTool.args = -m $local $other $base $output + myHtmlTool.regkey = Software\FooSoftware\HtmlMerge + myHtmlTool.priority = 1 + + Supported arguments: + priority;; + The priority in which to evaluate this tool. + Default: 0. + executable;; + Either just the name of the executable or its pathname. + Default: the tool name. + args;; + The arguments to pass to the tool executable. You can refer to the files + being merged as well as the output file through these variables: $base, + $local, $other, $output. + Default: $local $base $other + premerge;; + Attempt to run internal non-interactive 3-way merge tool before + launching external tool. + Default: True + binary;; + This tool can merge binary files. Defaults to False, unless tool + was selected by file pattern match. + symlink;; + This tool can merge symlinks. Defaults to False, even if tool was + selected by file pattern match. + checkconflicts;; + Check whether there are conflicts even though the tool reported + success. + Default: False + checkchanged;; + Check whether outputs were written even though the tool reported + success. + Default: False + fixeol;; + Attempt to fix up EOL changes caused by the merge tool. + Default: False + gui:; + This tool requires a graphical interface to run. Default: False + regkey;; + Windows registry key which describes install location of this tool. + Mercurial will search for this key first under HKEY_CURRENT_USER and + then under HKEY_LOCAL_MACHINE. Default: None + regname;; + Name of value to read from specified registry key. Defaults to the + unnamed (default) value. + regappend;; + String to append to the value read from the registry, typically the + executable name of the tool. Default: None + hooks:: Commands or Python functions that get automatically executed by various actions such as starting or finishing a commit. Multiple @@ -453,7 +529,18 @@ Template string for commands that print changesets. merge;; The conflict resolution program to use during a manual merge. - Default is "hgmerge". + There are some internal tools available: + + internal:local;; + keep the local version + internal:other;; + use the other version + internal:merge;; + use the internal non-interactive merge tool + internal:fail;; + fail to merge + + See the merge-tools section for more information on configuring tools. patch;; command to use to apply patches. Look for 'gpatch' or 'patch' in PATH if unset. diff -r 90e5c82a3859 -r 50a277e6ceae doc/ja/hgmerge.1.ja.txt --- a/doc/ja/hgmerge.1.ja.txt Mon Feb 18 19:20:22 2008 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -HGMERGE(1) -========== -Matt Mackall -v0.1, 27 May 2005 - -名前 --- -hgmerge - Mercurial ソースコード管理システムでファイルをマージする -のに使われるデフォルトのラッパー - -書式 --- -'hgmerge' local ancestor remote - -説明 --- -hgmerge(1) コマンドは Mercurial システムでファイルをマージするため -のグラフィカルなインターフェイスを提供します。これは kdiff3, -merge(1), tkdiff(1), または単純に diff(1) と patch(1) のラッパーで、 -どれがシステム上にあるかに依存します。 - -hgmerge(1) は Mercurial ソースコード管理システムで環境変数 -HGMERGE が設定されていない場合に使われます。 - -著者 --- -Vincent Danjean によって書かれました。 - -関連情報 --- -hg(1) - Mercurial システムへのコマンドラインインターフェイス - -著作権情報 ----- -Copyright (C) 2005-2007 Matt Mackall. -このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで -認められます。 diff -r 90e5c82a3859 -r 50a277e6ceae hgext/convert/__init__.py --- a/hgext/convert/__init__.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/convert/__init__.py Mon Feb 18 19:21:33 2008 +0100 @@ -19,6 +19,7 @@ - Darcs - git - Subversion + - GNU Arch Accepted destination formats: - Mercurial diff -r 90e5c82a3859 -r 50a277e6ceae hgext/convert/common.py --- a/hgext/convert/common.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/convert/common.py Mon Feb 18 19:21:33 2008 +0100 @@ -30,8 +30,8 @@ class commit(object): def __init__(self, author, date, desc, parents, branch=None, rev=None, extra={}): - self.author = author - self.date = date + self.author = author or 'unknown' + self.date = date or '0 0' self.desc = desc self.parents = parents self.branch = branch @@ -227,7 +227,7 @@ except TypeError: pass cmdline = [util.shellquote(arg) for arg in cmdline] - cmdline += ['<', util.nulldev] + cmdline += ['2>', util.nulldev, '<', util.nulldev] cmdline = ' '.join(cmdline) self.ui.debug(cmdline, '\n') return cmdline @@ -246,6 +246,12 @@ self.ui.debug(output) return output, fp.close() + def runlines(self, cmd, *args, **kwargs): + fp = self._run(cmd, *args, **kwargs) + output = fp.readlines() + self.ui.debug(''.join(output)) + return output, fp.close() + def checkexit(self, status, output=''): if status: if output: @@ -259,6 +265,11 @@ self.checkexit(status, output) return output + def runlines0(self, cmd, *args, **kwargs): + output, status = self.runlines(cmd, *args, **kwargs) + self.checkexit(status, ''.join(output)) + return output + def getargmax(self): if '_argmax' in self.__dict__: return self._argmax @@ -311,6 +322,8 @@ self._read() def _read(self): + if self.path is None: + return try: fp = open(self.path, 'r') except IOError, err: diff -r 90e5c82a3859 -r 50a277e6ceae hgext/convert/convcmd.py --- a/hgext/convert/convcmd.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/convert/convcmd.py Mon Feb 18 19:21:33 2008 +0100 @@ -11,18 +11,28 @@ from git import convert_git from hg import mercurial_source, mercurial_sink from subversion import debugsvnlog, svn_source, svn_sink +from gnuarch import gnuarch_source import filemap import os, shutil from mercurial import hg, util from mercurial.i18n import _ +orig_encoding = 'ascii' + +def recode(s): + if isinstance(s, unicode): + return s.encode(orig_encoding, 'replace') + else: + return s.decode('utf-8').encode(orig_encoding, 'replace') + source_converters = [ ('cvs', convert_cvs), ('git', convert_git), ('svn', svn_source), ('hg', mercurial_source), ('darcs', darcs_source), + ('gnuarch', gnuarch_source), ] sink_converters = [ @@ -74,6 +84,8 @@ self.readauthormap(opts.get('authors')) self.authorfile = self.dest.authorfile() + self.splicemap = mapfile(ui, ui.config('convert', 'splicemap')) + def walktree(self, heads): '''Return a mapping that identifies the uncommitted parents of every uncommitted changeset.''' @@ -98,6 +110,7 @@ visit = parents.keys() seen = {} children = {} + actives = [] while visit: n = visit.pop(0) @@ -106,49 +119,63 @@ # Ensure that nodes without parents are present in the 'children' # mapping. children.setdefault(n, []) + hasparent = False for p in parents[n]: if not p in self.map: visit.append(p) + hasparent = True children.setdefault(p, []).append(n) + if not hasparent: + actives.append(n) + + del seen + del visit + + if self.opts.get('datesort'): + dates = {} + def getdate(n): + if n not in dates: + dates[n] = util.parsedate(self.commitcache[n].date) + return dates[n] + + def picknext(nodes): + return min([(getdate(n), n) for n in nodes])[1] + else: + prev = [None] + def picknext(nodes): + # Return the first eligible child of the previously converted + # revision, or any of them. + next = nodes[0] + for n in nodes: + if prev[0] in parents[n]: + next = n + break + prev[0] = next + return next s = [] - removed = {} - visit = children.keys() - while visit: - n = visit.pop(0) - if n in removed: continue - dep = 0 - if n in parents: - for p in parents[n]: - if p in self.map: continue - if p not in removed: - # we're still dependent - visit.append(n) - dep = 1 - break + pendings = {} + while actives: + n = picknext(actives) + actives.remove(n) + s.append(n) - if not dep: - # all n's parents are in the list - removed[n] = 1 - if n not in self.map: - s.append(n) - if n in children: - for c in children[n]: - visit.insert(0, c) + # Update dependents list + for c in children.get(n, []): + if c not in pendings: + pendings[c] = [p for p in parents[c] if p not in self.map] + try: + pendings[c].remove(n) + except ValueError: + raise util.Abort(_('cycle detected between %s and %s') + % (recode(c), recode(n))) + if not pendings[c]: + # Parents are converted, node is eligible + actives.insert(0, c) + pendings[c] = None - if self.opts.get('datesort'): - depth = {} - for n in s: - depth[n] = 0 - pl = [p for p in self.commitcache[n].parents - if p not in self.map] - if pl: - depth[n] = max([depth[p] for p in pl]) + 1 - - s = [(depth[n], util.parsedate(self.commitcache[n].date), n) - for n in s] - s.sort() - s = [e[2] for e in s] + if len(s) != len(parents): + raise util.Abort(_("not all revisions were sorted")) return s @@ -224,16 +251,18 @@ # Merely marks that a copy happened. self.dest.copyfile(copyf, f) - parents = [b[0] for b in pbranches] + try: + parents = [self.splicemap[rev]] + self.ui.debug('spliced in %s as parents of %s\n' % + (parents, rev)) + except KeyError: + parents = [b[0] for b in pbranches] newnode = self.dest.putcommit(filenames, parents, commit) self.source.converted(rev, newnode) self.map[rev] = newnode def convert(self): - def recode(s): - return s.decode('utf-8').encode(orig_encoding, 'replace') - try: self.source.before() self.dest.before() @@ -284,8 +313,6 @@ self.source.after() self.map.close() -orig_encoding = 'ascii' - def convert(ui, src, dest=None, revmapfile=None, **opts): global orig_encoding orig_encoding = util._encoding diff -r 90e5c82a3859 -r 50a277e6ceae hgext/convert/cvs.py --- a/hgext/convert/cvs.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/convert/cvs.py Mon Feb 18 19:21:33 2008 +0100 @@ -71,7 +71,7 @@ elif l.startswith("Ancestor branch"): ancestor = l[17:-1] # figure out the parent later - self.parent[id] = None + self.parent[id] = self.lastbranch[ancestor] elif l.startswith("Author"): author = self.recode(l[8:-1]) elif l.startswith("Tag:") or l.startswith("Tags:"): @@ -101,13 +101,14 @@ p = [] if branch == "HEAD": branch = "" - if branch and p[0] == None: + if branch: latest = None # the last changeset that contains a base # file is our parent for r in oldrevs: - latest = max(filerevids[r], latest) - p = [latest] + latest = max(filerevids.get(r, None), latest) + if latest: + p = [latest] # add current commit to set c = commit(author=author, date=date, parents=p, diff -r 90e5c82a3859 -r 50a277e6ceae hgext/convert/git.py --- a/hgext/convert/git.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/convert/git.py Mon Feb 18 19:21:33 2008 +0100 @@ -102,7 +102,6 @@ tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:] tz = -int(tzs) * (int(tzh) * 3600 + int(tzm)) date = tm + " " + str(tz) - author = author or "unknown" c = commit(parents=parents, date=date, author=author, desc=message, rev=version) diff -r 90e5c82a3859 -r 50a277e6ceae hgext/convert/gnuarch.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/convert/gnuarch.py Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,301 @@ +# GNU Arch support for the convert extension + +from common import NoRepo, checktool, commandline, commit, converter_source +from mercurial.i18n import _ +from mercurial import util +import os, shutil, tempfile, stat + +class gnuarch_source(converter_source, commandline): + + class gnuarch_rev: + def __init__(self, rev): + self.rev = rev + self.summary = '' + self.date = None + self.author = '' + self.add_files = [] + self.mod_files = [] + self.del_files = [] + self.ren_files = {} + self.ren_dirs = {} + + def __init__(self, ui, path, rev=None): + super(gnuarch_source, self).__init__(ui, path, rev=rev) + + if not os.path.exists(os.path.join(path, '{arch}')): + raise NoRepo(_("%s does not look like a GNU Arch repo" % path)) + + # Could use checktool, but we want to check for baz or tla. + self.execmd = None + if util.find_exe('baz'): + self.execmd = 'baz' + else: + if util.find_exe('tla'): + self.execmd = 'tla' + else: + raise util.Abort(_('cannot find a GNU Arch tool')) + + commandline.__init__(self, ui, self.execmd) + + self.path = os.path.realpath(path) + self.tmppath = None + + self.treeversion = None + self.lastrev = None + self.changes = {} + self.parents = {} + self.tags = {} + self.modecache = {} + + def before(self): + 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) + + # Read author, date and summary + catlog = self.runlines0('cat-log', '-d', self.path, rev) + self._parsecatlog(catlog, rev) + + self.parents[rev] = child + child = [rev] + if rev == self.rev: + break + self.parents[None] = child + + def after(self): + self.ui.debug(_('cleaning up %s\n' % self.tmppath)) + shutil.rmtree(self.tmppath, ignore_errors=True) + + def getheads(self): + return self.parents[None] + + def getfile(self, name, rev): + if rev != self.lastrev: + raise util.Abort(_('internal calling inconsistency')) + + # Raise IOError if necessary (i.e. deleted files). + if not os.path.exists(os.path.join(self.tmppath, name)): + raise IOError + + data, mode = self._getfile(name, rev) + self.modecache[(name, rev)] = mode + + return data + + def getmode(self, name, rev): + return self.modecache[(name, rev)] + + def getchanges(self, rev): + self.modecache = {} + self._update(rev) + changes = [] + copies = {} + + for f in self.changes[rev].add_files: + changes.append((f, rev)) + + for f in self.changes[rev].mod_files: + changes.append((f, rev)) + + for f in self.changes[rev].del_files: + changes.append((f, rev)) + + for src in self.changes[rev].ren_files: + to = self.changes[rev].ren_files[src] + changes.append((src, rev)) + changes.append((to, rev)) + copies[src] = to + + for src in self.changes[rev].ren_dirs: + to = self.changes[rev].ren_dirs[src] + chgs, cps = self._rendirchanges(src, to); + changes += [(f, rev) for f in chgs] + for c in cps: + copies[c] = cps[c] + + changes.sort() + self.lastrev = rev + + return changes, copies + + def getcommit(self, rev): + changes = self.changes[rev] + return commit(author = changes.author, date = changes.date, + desc = changes.summary, parents = self.parents[rev]) + + def gettags(self): + return self.tags + + def _execute(self, cmd, *args, **kwargs): + cmdline = [self.execmd, cmd] + cmdline += args + cmdline = [util.shellquote(arg) for arg in cmdline] + cmdline += ['>', util.nulldev, '2>', util.nulldev] + cmdline = util.quotecommand(' '.join(cmdline)) + self.ui.debug(cmdline, '\n') + return os.system(cmdline) + + def _update(self, rev): + if rev == 'base-0': + # Initialise 'base-0' revision + 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) + + def _getfile(self, name, rev): + mode = os.lstat(os.path.join(self.tmppath, name)).st_mode + if stat.S_ISLNK(mode): + data = os.readlink(os.path.join(self.tmppath, name)) + mode = mode and 'l' or '' + else: + data = open(os.path.join(self.tmppath, name), 'rb').read() + mode = (mode & 0111) and 'x' or '' + return data, mode + + def _exclude(self, name): + exclude = [ '{arch}', '.arch-ids', '.arch-inventory' ] + for exc in exclude: + if name.find(exc) != -1: + return True + return False + + def _readcontents(self, path): + files = [] + contents = os.listdir(path) + while len(contents) > 0: + c = contents.pop() + p = os.path.join(path, c) + # os.walk could be used, but here we avoid internal GNU + # Arch files and directories, thus saving a lot time. + if not self._exclude(p): + if os.path.isdir(p): + contents += [os.path.join(c, f) for f in os.listdir(p)] + else: + files.append(c) + return files + + def _rendirchanges(self, src, dest): + changes = [] + copies = {} + files = self._readcontents(os.path.join(self.tmppath, dest)) + for f in files: + s = os.path.join(src, f) + d = os.path.join(dest, f) + changes.append(s) + changes.append(d) + copies[s] = d + return changes, copies + + 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) + self.checkexit(output) + self.ui.debug(_('analysing revision %s...\n' % rev)) + files = self._readcontents(self.tmppath) + self.changes[rev].add_files += files + + def _stripbasepath(self, path): + if path.startswith('./'): + return path[2:] + 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) + + def _parsechangeset(self, data, rev): + for l in data: + l = l.strip() + # Added file (ignore added directory) + if l.startswith('A') and not l.startswith('A/'): + file = self._stripbasepath(l[1:].strip()) + if not self._exclude(file): + self.changes[rev].add_files.append(file) + # Deleted file (ignore deleted directory) + elif l.startswith('D') and not l.startswith('D/'): + file = self._stripbasepath(l[1:].strip()) + if not self._exclude(file): + self.changes[rev].del_files.append(file) + # Modified binary file + elif l.startswith('Mb'): + file = self._stripbasepath(l[2:].strip()) + if not self._exclude(file): + self.changes[rev].mod_files.append(file) + # Modified link + elif l.startswith('M->'): + file = self._stripbasepath(l[3:].strip()) + if not self._exclude(file): + self.changes[rev].mod_files.append(file) + # Modified file + elif l.startswith('M'): + file = self._stripbasepath(l[1:].strip()) + if not self._exclude(file): + self.changes[rev].mod_files.append(file) + # Renamed file (or link) + elif l.startswith('=>'): + files = l[2:].strip().split(' ') + if len(files) == 1: + files = l[2:].strip().split('\t') + src = self._stripbasepath(files[0]) + dst = self._stripbasepath(files[1]) + if not self._exclude(src) and not self._exclude(dst): + self.changes[rev].ren_files[src] = dst + # Conversion from file to link or from link to file (modified) + elif l.startswith('ch'): + file = self._stripbasepath(l[2:].strip()) + if not self._exclude(file): + self.changes[rev].mod_files.append(file) + # Renamed directory + elif l.startswith('/>'): + dirs = l[2:].strip().split(' ') + if len(dirs) == 1: + dirs = l[2:].strip().split('\t') + src = self._stripbasepath(dirs[0]) + dst = self._stripbasepath(dirs[1]) + if not self._exclude(src) and not self._exclude(dst): + self.changes[rev].ren_dirs[src] = dst diff -r 90e5c82a3859 -r 50a277e6ceae hgext/convert/subversion.py --- a/hgext/convert/subversion.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/convert/subversion.py Mon Feb 18 19:21:33 2008 +0100 @@ -947,7 +947,7 @@ os.rename(tempname, wdest) def dirs_of(self, files): - dirs = set() + dirs = util.set() for f in files: if os.path.isdir(self.wjoin(f)): dirs.add(f) @@ -970,7 +970,8 @@ def tidy_dirs(self, names): dirs = list(self.dirs_of(names)) - dirs.sort(reverse=True) + dirs.sort() + dirs.reverse() deleted = [] for d in dirs: wd = self.wjoin(d) @@ -991,7 +992,7 @@ return self.revid(self.childmap[parent]) except KeyError: pass - entries = set(self.delete) + entries = util.set(self.delete) files = util.frozenset(files) entries.update(self.add_dirs(files.difference(entries))) if self.copies: diff -r 90e5c82a3859 -r 50a277e6ceae hgext/extdiff.py --- a/hgext/extdiff.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/extdiff.py Mon Feb 18 19:21:33 2008 +0100 @@ -80,13 +80,18 @@ '''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.''' - dirname = os.path.basename(repo.root) + repo_root = repo.root + + dirname = os.path.basename(repo_root) if dirname == "": dirname = "root" base = os.path.join(tmproot, dirname) os.mkdir(base) ui.note(_('making snapshot of %d files from working dir\n') % (len(files))) + + fns_and_mtime = [] + for fn in files: wfn = util.pconvert(fn) ui.note(' %s\n' % wfn) @@ -94,13 +99,27 @@ destdir = os.path.dirname(dest) if not os.path.isdir(destdir): os.makedirs(destdir) + fp = open(dest, 'wb') for chunk in util.filechunkiter(repo.wopener(wfn)): fp.write(chunk) - return dirname + fp.close() + + fns_and_mtime.append((dest, os.path.join(repo_root, fn), + os.path.getmtime(dest))) + + + return dirname, fns_and_mtime def dodiff(ui, repo, diffcmd, diffopts, pats, opts): + '''Do the actuall diff: + + - copy to a temp structure if diffing 2 internal revisions + - copy to a temp structure if diffing working revision with + 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']) files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) modified, added, removed, deleted, unknown = repo.status( @@ -115,11 +134,17 @@ dir1 = snapshot_node(ui, repo, modified + removed, node1, tmproot) changes = len(modified) + len(removed) + len(added) + fns_and_mtime = [] + # If node2 in not the wc or there is >1 change, copy it if node2: dir2 = snapshot_node(ui, repo, modified + added, node2, tmproot) elif changes > 1: - dir2 = snapshot_wdir(ui, repo, modified + added, tmproot) + #we only actually need to get the files to copy back to the working + #dir in this case (because the other cases are: diffing 2 revisions + #or single file -- in which case the file is already directly passed + #to the diff tool). + dir2, fns_and_mtime = snapshot_wdir(ui, repo, modified + added, tmproot) else: # This lets the diff tool open the changed file directly dir2 = '' @@ -142,6 +167,13 @@ util.shellquote(dir1), util.shellquote(dir2))) ui.debug('running %r in %s\n' % (cmdline, tmproot)) util.system(cmdline, cwd=tmproot) + + for copy_fn, working_fn, mtime in fns_and_mtime: + if os.path.getmtime(copy_fn) != mtime: + ui.debug('File changed while diffing. ' + 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn)) + util.copyfile(copy_fn, working_fn) + return 1 finally: ui.note(_('cleaning up temp directory\n')) diff -r 90e5c82a3859 -r 50a277e6ceae hgext/fetch.py --- a/hgext/fetch.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/fetch.py Mon Feb 18 19:21:33 2008 +0100 @@ -65,6 +65,10 @@ modheads = repo.pull(other, heads=revs) return postincoming(other, modheads) + date = opts.get('date') + if date: + opts['date'] = util.parsedate(date) + parent, p2 = repo.dirstate.parents() if parent != repo.changelog.tip(): raise util.Abort(_('working dir not at tip ' diff -r 90e5c82a3859 -r 50a277e6ceae hgext/gpg.py --- a/hgext/gpg.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/gpg.py Mon Feb 18 19:21:33 2008 +0100 @@ -203,6 +203,11 @@ mygpg = newgpg(ui, **opts) sigver = "0" sigmessage = "" + + date = opts.get('date') + if date: + opts['date'] = util.parsedate(date) + if revs: nodes = [repo.lookup(n) for n in revs] else: diff -r 90e5c82a3859 -r 50a277e6ceae hgext/imerge.py --- a/hgext/imerge.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/imerge.py Mon Feb 18 19:21:33 2008 +0100 @@ -7,7 +7,8 @@ from mercurial.i18n import _ from mercurial.node import * -from mercurial import commands, cmdutil, dispatch, fancyopts, hg, merge, util +from mercurial import commands, cmdutil, dispatch, fancyopts +from mercurial import hg, filemerge, util import os, tarfile class InvalidStateFileException(Exception): pass @@ -126,7 +127,7 @@ self.wctx._parents.pop() try: # TODO: we should probably revert the file if merge fails - return merge.filemerge(self.repo, fn, fd, fo, self.wctx, p2) + return filemerge.filemerge(self.repo, fn, fd, fo, self.wctx, p2) finally: self.wctx._parents.append(p2) if realmerge: @@ -135,13 +136,13 @@ del os.environ['HGMERGE'] def start(self, rev=None): - _filemerge = merge.filemerge - def filemerge(repo, fw, fd, fo, wctx, mctx): + _filemerge = filemerge.filemerge + def filemerge_(repo, fw, fd, fo, wctx, mctx): self.conflicts[fw] = (fd, fo) - merge.filemerge = filemerge + filemerge.filemerge = filemerge_ commands.merge(self.ui, self.repo, rev=rev) - merge.filemerge = _filemerge + filemerge.filemerge = _filemerge self.wctx = self.repo.workingctx() self.save() diff -r 90e5c82a3859 -r 50a277e6ceae hgext/keyword.py --- a/hgext/keyword.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/keyword.py Mon Feb 18 19:21:33 2008 +0100 @@ -80,23 +80,73 @@ from mercurial import commands, cmdutil, context, dispatch, filelog, revlog from mercurial import patch, localrepo, templater, templatefilters, util +from mercurial.hgweb import webcommands from mercurial.node import * from mercurial.i18n import _ -import re, shutil, sys, tempfile, time +import re, shutil, tempfile, time commands.optionalrepo += ' kwdemo' +# hg commands that do not act on keywords +nokwcommands = ('add addremove bundle copy export grep identify incoming init' + ' log outgoing push remove rename rollback tip' + ' convert email glog') + # hg commands that trigger expansion only when writing to working dir, # not when reading filelog, and unexpand when reading from working dir -restricted = ('diff1', 'record', - 'qfold', 'qimport', 'qnew', 'qpush', 'qrefresh', 'qrecord') +restricted = 'record qfold qimport qnew qpush qrefresh qrecord' def utcdate(date): '''Returns hgdate in cvs-like UTC format.''' return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0])) -_kwtemplater = None +# make keyword tools accessible +kwtools = {'templater': None, 'hgcmd': None} + +# store originals of monkeypatches +_patchfile_init = patch.patchfile.__init__ +_patch_diff = patch.diff +_dispatch_parse = dispatch._parse + +def _kwpatchfile_init(self, ui, fname, missing=False): + '''Monkeypatch/wrap patch.patchfile.__init__ to avoid + rejects or conflicts due to expanded keywords in working dir.''' + _patchfile_init(self, ui, fname, missing=missing) + # shrink keywords read from working dir + kwt = kwtools['templater'] + self.lines = kwt.shrinklines(self.fname, self.lines) + +def _kw_diff(repo, node1=None, node2=None, files=None, match=util.always, + fp=None, changes=None, opts=None): + '''Monkeypatch patch.diff to avoid expansion except when + comparing against working dir.''' + if node2 is not None: + kwtools['templater'].matcher = util.never + elif node1 is not None and node1 != repo.changectx().node(): + kwtools['templater'].restrict = True + _patch_diff(repo, node1=node1, node2=node2, files=files, match=match, + fp=fp, changes=changes, opts=opts) + +def _kwweb_changeset(web, req, tmpl): + '''Wraps webcommands.changeset turning off keyword expansion.''' + kwtools['templater'].matcher = util.never + return web.changeset(tmpl, web.changectx(req)) + +def _kwweb_filediff(web, req, tmpl): + '''Wraps webcommands.filediff turning off keyword expansion.''' + kwtools['templater'].matcher = util.never + return web.filediff(tmpl, web.filectx(req)) + +def _kwdispatch_parse(ui, args): + '''Monkeypatch dispatch._parse to obtain running hg command.''' + cmd, func, args, options, cmdoptions = _dispatch_parse(ui, args) + kwtools['hgcmd'] = cmd + return cmd, func, args, options, cmdoptions + +# dispatch._parse is run before reposetup, so wrap it here +dispatch._parse = _kwdispatch_parse + class kwtemplater(object): ''' @@ -113,13 +163,11 @@ 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}', } - def __init__(self, ui, repo, inc, exc, hgcmd): + def __init__(self, ui, repo, inc, exc): self.ui = ui self.repo = repo self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1] - self.hgcmd = hgcmd - self.commitnode = None - self.path = '' + self.restrict = kwtools['hgcmd'] in restricted.split() kwmaps = self.ui.configitems('keywordmaps') if kwmaps: # override default templates @@ -134,47 +182,89 @@ self.ct = cmdutil.changeset_templater(self.ui, self.repo, False, '', False) - def substitute(self, node, data, subfunc): - '''Obtains file's changenode if commit node not given, - and calls given substitution function.''' - if self.commitnode: - fnode = self.commitnode - else: - c = context.filectx(self.repo, self.path, fileid=node) - fnode = c.node() + def getnode(self, path, fnode): + '''Derives changenode from file path and filenode.''' + # used by kwfilelog.read and kwexpand + c = context.filectx(self.repo, path, fileid=fnode) + return c.node() + def substitute(self, data, path, node, subfunc): + '''Replaces keywords in data with expanded template.''' def kwsub(mobj): - '''Substitutes keyword using corresponding template.''' kw = mobj.group(1) self.ct.use_template(self.templates[kw]) self.ui.pushbuffer() - self.ct.show(changenode=fnode, root=self.repo.root, file=self.path) - return '$%s: %s $' % (kw, templatefilters.firstline( - self.ui.popbuffer())) - + self.ct.show(changenode=node, root=self.repo.root, file=path) + ekw = templatefilters.firstline(self.ui.popbuffer()) + return '$%s: %s $' % (kw, ekw) return subfunc(kwsub, data) - def expand(self, node, data): + def expand(self, path, node, data): '''Returns data with keywords expanded.''' - if util.binary(data) or self.hgcmd in restricted: - return data - return self.substitute(node, data, self.re_kw.sub) + if not self.restrict and self.matcher(path) and not util.binary(data): + changenode = self.getnode(path, node) + return self.substitute(data, path, changenode, self.re_kw.sub) + return data + + def iskwfile(self, path, islink): + '''Returns true if path matches [keyword] pattern + and is not a symbolic link. + Caveat: localrepository._link fails on Windows.''' + return self.matcher(path) and not islink(path) - def process(self, node, data, expand): - '''Returns a tuple: data, count. - Count is number of keywords/keyword substitutions, - telling caller whether to act on file containing data.''' - if util.binary(data): - return data, None - if expand: - return self.substitute(node, data, self.re_kw.subn) - return data, self.re_kw.search(data) + def overwrite(self, node=None, expand=True, files=None): + '''Overwrites selected files expanding/shrinking keywords.''' + ctx = self.repo.changectx(node) + mf = ctx.manifest() + if node is not None: # commit + files = [f for f in ctx.files() if f in mf] + notify = self.ui.debug + else: # kwexpand/kwshrink + notify = self.ui.note + candidates = [f for f in files if self.iskwfile(f, mf.linkf)] + if candidates: + self.restrict = True # do not expand when reading + candidates.sort() + action = expand and 'expanding' or 'shrinking' + for f in candidates: + fp = self.repo.file(f) + data = fp.read(mf[f]) + if util.binary(data): + continue + if expand: + changenode = node or self.getnode(f, mf[f]) + data, found = self.substitute(data, f, changenode, + self.re_kw.subn) + else: + found = self.re_kw.search(data) + if found: + notify(_('overwriting %s %s keywords\n') % (f, action)) + self.repo.wwrite(f, data, mf.flags(f)) + self.repo.dirstate.normal(f) + self.restrict = False - def shrink(self, text): + def shrinktext(self, text): + '''Unconditionally removes all keyword substitutions from text.''' + return self.re_kw.sub(r'$\1$', text) + + def shrink(self, fname, text): '''Returns text with all keyword substitutions removed.''' - if util.binary(text): - return text - return self.re_kw.sub(r'$\1$', text) + if self.matcher(fname) and not util.binary(text): + return self.shrinktext(text) + return text + + def shrinklines(self, fname, lines): + '''Returns lines with keyword substitutions removed.''' + if self.matcher(fname): + text = ''.join(lines) + if not util.binary(text): + return self.shrinktext(text).splitlines(True) + return lines + + def wread(self, fname, data): + '''If in restricted mode returns data read from wdir with + keyword substitutions removed.''' + return self.restrict and self.shrink(fname, data) or data class kwfilelog(filelog.filelog): ''' @@ -183,84 +273,41 @@ ''' def __init__(self, opener, path): super(kwfilelog, self).__init__(opener, path) - _kwtemplater.path = path - - def kwctread(self, node, expand): - '''Reads expanding and counting keywords, called from _overwrite.''' - data = super(kwfilelog, self).read(node) - return _kwtemplater.process(node, data, expand) + self.kwt = kwtools['templater'] + self.path = path def read(self, node): '''Expands keywords when reading filelog.''' data = super(kwfilelog, self).read(node) - return _kwtemplater.expand(node, data) + return self.kwt.expand(self.path, node, data) def add(self, text, meta, tr, link, p1=None, p2=None): '''Removes keyword substitutions when adding to filelog.''' - text = _kwtemplater.shrink(text) + text = self.kwt.shrink(self.path, text) return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2) def cmp(self, node, text): '''Removes keyword substitutions for comparison.''' - text = _kwtemplater.shrink(text) + text = self.kwt.shrink(self.path, text) if self.renamed(node): t2 = super(kwfilelog, self).read(node) return t2 != text return revlog.revlog.cmp(self, node, text) - -# store original patch.patchfile.__init__ -_patchfile_init = patch.patchfile.__init__ - -def _kwpatchfile_init(self, ui, fname, missing=False): - '''Monkeypatch/wrap patch.patchfile.__init__ to avoid - rejects or conflicts due to expanded keywords in working dir.''' - _patchfile_init(self, ui, fname, missing=missing) - - if _kwtemplater.matcher(self.fname): - # shrink keywords read from working dir - kwshrunk = _kwtemplater.shrink(''.join(self.lines)) - self.lines = kwshrunk.splitlines(True) - - -def _iskwfile(f, link): - return not link(f) and _kwtemplater.matcher(f) - -def _status(ui, repo, *pats, **opts): +def _status(ui, repo, kwt, *pats, **opts): '''Bails out if [keyword] configuration is not active. Returns status of working directory.''' - if _kwtemplater: + if kwt: files, match, anypats = cmdutil.matchpats(repo, pats, opts) return repo.status(files=files, match=match, list_clean=True) if ui.configitems('keyword'): raise util.Abort(_('[keyword] patterns cannot match')) raise util.Abort(_('no [keyword] patterns configured')) -def _overwrite(ui, repo, node=None, expand=True, files=None): - '''Overwrites selected files expanding/shrinking keywords.''' - ctx = repo.changectx(node) - mf = ctx.manifest() - if node is not None: # commit - _kwtemplater.commitnode = node - files = [f for f in ctx.files() if f in mf] - notify = ui.debug - else: # kwexpand/kwshrink - notify = ui.note - candidates = [f for f in files if _iskwfile(f, mf.linkf)] - if candidates: - candidates.sort() - action = expand and 'expanding' or 'shrinking' - for f in candidates: - fp = repo.file(f, kwmatch=True) - data, kwfound = fp.kwctread(mf[f], expand) - if kwfound: - notify(_('overwriting %s %s keywords\n') % (f, action)) - repo.wwrite(f, data, mf.flags(f)) - repo.dirstate.normal(f) - def _kwfwrite(ui, repo, expand, *pats, **opts): - '''Selects files and passes them to _overwrite.''' - status = _status(ui, repo, *pats, **opts) + '''Selects files and passes them to kwtemplater.overwrite.''' + kwt = kwtools['templater'] + status = _status(ui, repo, kwt, *pats, **opts) modified, added, removed, deleted, unknown, ignored, clean = status if modified or added or removed or deleted: raise util.Abort(_('outstanding uncommitted changes in given files')) @@ -268,7 +315,7 @@ try: wlock = repo.wlock() lock = repo.lock() - _overwrite(ui, repo, expand=expand, files=clean) + kwt.overwrite(expand=expand, files=clean) finally: del wlock, lock @@ -370,13 +417,16 @@ keyword expansion. That is, files matched by [keyword] config patterns but not symlinks. ''' - status = _status(ui, repo, *pats, **opts) + kwt = kwtools['templater'] + status = _status(ui, repo, kwt, *pats, **opts) modified, added, removed, deleted, unknown, ignored, clean = status files = modified + added + clean if opts.get('untracked'): files += unknown files.sort() - kwfiles = [f for f in files if _iskwfile(f, repo._link)] + wctx = repo.workingctx() + islink = lambda p: 'l' in wctx.fileflags(p) + kwfiles = [f for f in files if kwt.iskwfile(f, islink)] cwd = pats and repo.getcwd() or '' kwfstats = not opts.get('ignore') and (('K', kwfiles),) or () if opts.get('all') or opts.get('ignore'): @@ -407,28 +457,15 @@ This is done for local repos only, and only if there are files configured at all for keyword substitution.''' - if not repo.local(): - return + try: + if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split() + or '.hg' in util.splitpath(repo.root) + or repo._url.startswith('bundle:')): + return + except AttributeError: + pass - nokwcommands = ('add', 'addremove', 'bundle', 'clone', 'copy', - 'export', 'grep', 'identify', 'incoming', 'init', - 'log', 'outgoing', 'push', 'remove', 'rename', - 'rollback', 'tip', - 'convert') - hgcmd, func, args, opts, cmdopts = dispatch._parse(ui, sys.argv[1:]) - if hgcmd in nokwcommands: - return - - if hgcmd == 'diff': - # only expand if comparing against working dir - node1, node2 = cmdutil.revpair(repo, cmdopts.get('rev')) - if node2 is not None: - return - # shrink if rev is not current node - if node1 is not None and node1 != repo.changectx().node(): - hgcmd = 'diff1' - - inc, exc = [], ['.hgtags'] + inc, exc = [], ['.hg*'] for pat, opt in ui.configitems('keyword'): if opt != 'ignore': inc.append(pat) @@ -437,26 +474,21 @@ if not inc: return - global _kwtemplater - _kwtemplater = kwtemplater(ui, repo, inc, exc, hgcmd) + kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc) class kwrepo(repo.__class__): - def file(self, f, kwmatch=False): + def file(self, f): if f[0] == '/': f = f[1:] - if kwmatch or _kwtemplater.matcher(f): - return kwfilelog(self.sopener, f) - return filelog.filelog(self.sopener, f) + return kwfilelog(self.sopener, f) def wread(self, filename): data = super(kwrepo, self).wread(filename) - if hgcmd in restricted and _kwtemplater.matcher(filename): - return _kwtemplater.shrink(data) - return data + return kwt.wread(filename, data) def commit(self, files=None, text='', user=None, date=None, match=util.always, force=False, force_editor=False, - p1=None, p2=None, extra={}): + p1=None, p2=None, extra={}, empty_ok=False): wlock = lock = None _p1 = _p2 = None try: @@ -484,13 +516,14 @@ self).commit(files=files, text=text, user=user, date=date, match=match, force=force, force_editor=force_editor, - p1=p1, p2=p2, extra=extra) + p1=p1, p2=p2, extra=extra, + empty_ok=empty_ok) # restore commit hooks for name, cmd in commithooks.iteritems(): ui.setconfig('hooks', name, cmd) if node is not None: - _overwrite(ui, self, node=node) + kwt.overwrite(node=node) repo.hook('commit', node=node, parent1=_p1, parent2=_p2) return node finally: @@ -498,6 +531,9 @@ repo.__class__ = kwrepo patch.patchfile.__init__ = _kwpatchfile_init + patch.diff = _kw_diff + webcommands.changeset = webcommands.rev = _kwweb_changeset + webcommands.filediff = webcommands.diff = _kwweb_filediff cmdtable = { diff -r 90e5c82a3859 -r 50a277e6ceae hgext/mq.py --- a/hgext/mq.py Mon Feb 18 19:20:22 2008 +0100 +++ b/hgext/mq.py Mon Feb 18 19:21:33 2008 +0100 @@ -600,11 +600,21 @@ raise util.Abort(_("local changes found")) return m, a, r, d + _reserved = ('series', 'status', 'guards') + def check_reserved_name(self, name): + if (name in self._reserved or name.startswith('.hg') + or name.startswith('.mq')): + raise util.Abort(_('"%s" cannot be used as the name of a patch') + % name) + def new(self, repo, patch, *pats, **opts): msg = opts.get('msg') force = opts.get('force') user = opts.get('user') date = opts.get('date') + if date: + date = util.parsedate(date) + self.check_reserved_name(patch) if os.path.exists(self.join(patch)): raise util.Abort(_('patch "%s" already exists') % patch) if opts.get('include') or opts.get('exclude') or pats: @@ -632,7 +642,7 @@ p.write("# HG changeset patch\n") if user: p.write("# User " + user + "\n") - p.write("# Date " + date + "\n") + p.write("# Date %d %d\n" % date) p.write("\n") elif user: p.write("From: " + user + "\n") @@ -872,10 +882,16 @@ start = info[0] rev = revlog.bin(info[1]) + if update: + top = self.check_toppatch(repo) + + if repo.changelog.heads(rev) != [revlog.bin(self.applied[-1].rev)]: + raise util.Abort("popping would remove a revision not " + "managed by this patch queue") + # we know there are no local changes, so we can make a simplified # form of hg.update. if update: - top = self.check_toppatch(repo) qp = self.qparents(repo, rev) changes = repo.changelog.read(qp) mmap = repo.manifest.read(changes[0]) @@ -898,8 +914,8 @@ except: pass repo.dirstate.forget(f) repo.dirstate.setparents(qp, revlog.nullid) + del self.applied[start:end] self.strip(repo, rev, update=False, backup='strip') - del self.applied[start:end] if len(self.applied): self.ui.write("Now at: %s\n" % self.applied[-1].name) else: @@ -921,11 +937,16 @@ if len(self.applied) == 0: self.ui.write("No patches applied\n") return 1 + newdate = opts.get('date') + if newdate: + newdate = '%d %d' % util.parsedate(newdate) wlock = repo.wlock() try: self.check_toppatch(repo) (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name) top = revlog.bin(top) + if repo.changelog.heads(top) != [top]: + raise util.Abort("cannot refresh a revision with children") cparents = repo.changelog.parents(top) patchparent = self.qparents(repo, top) message, comments, user, date, patchfound = self.readheaders(patchfn) @@ -979,7 +1000,6 @@ comments = ['From: ' + newuser, ''] + comments user = newuser - newdate = opts.get('date') if newdate: if setheaderfield(comments, ['# Date '], newdate): date = newdate @@ -1112,12 +1132,13 @@ if not user: user = changes[1] + self.applied.pop() + self.applied_dirty = 1 self.strip(repo, top, update=False, backup='strip') n = repo.commit(filelist, message, user, date, match=matchfn, force=1) - self.applied[-1] = statusentry(revlog.hex(n), patchfn) - self.applied_dirty = 1 + self.applied.append(statusentry(revlog.hex(n), patchfn)) self.removeundo(repo) else: self.printdiff(repo, patchparent, fp=patchf) @@ -1406,6 +1427,7 @@ if not patchname: patchname = normname('%d.diff' % r) + self.check_reserved_name(patchname) checkseries(patchname) checkfile(patchname) self.full_series.insert(0, patchname) @@ -1428,6 +1450,7 @@ raise util.Abort(_('-e is incompatible with import from -')) if not patchname: patchname = normname(filename) + self.check_reserved_name(patchname) if not os.path.isfile(self.join(patchname)): raise util.Abort(_("patch %s does not exist") % patchname) else: @@ -1437,11 +1460,12 @@ raise util.Abort(_('need --name to import a patch from -')) text = sys.stdin.read() else: - text = file(filename).read() + text = file(filename, 'rb').read() except IOError: raise util.Abort(_("unable to read %s") % patchname) if not patchname: patchname = normname(os.path.basename(filename)) + self.check_reserved_name(patchname) checkfile(patchname) patchf = self.opener(patchname, "w") patchf.write(text) @@ -1534,6 +1558,8 @@ if r: if not os.path.exists(r.wjoin('.hgignore')): fp = r.wopener('.hgignore', 'w') + fp.write('^\\.hg\n') + fp.write('^\\.mq\n') fp.write('syntax: glob\n') fp.write('status\n') fp.write('guards\n') @@ -2147,6 +2173,12 @@ return tagscache mqtags = [(revlog.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])) + return tagscache + mqtags.append((mqtags[-1][0], 'qtip')) mqtags.append((mqtags[0][0], 'qbase')) mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent')) @@ -2158,16 +2190,19 @@ return tagscache - def _branchtags(self): + def _branchtags(self, partial, lrev): q = self.mq if not q.applied: - return super(mqrepo, self)._branchtags() + return super(mqrepo, self)._branchtags(partial, lrev) - self.branchcache = {} # avoid recursion in changectx cl = self.changelog - partial, last, lrev = self._readbranchcache() + qbasenode = revlog.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)) + return super(mqrepo, self)._branchtags(partial, lrev) - qbase = cl.rev(revlog.bin(q.applied[0].rev)) + qbase = cl.rev(qbasenode) start = lrev + 1 if start < qbase: # update the cache (excluding the patches) and save it @@ -2213,8 +2248,9 @@ "^qdiff": (diff, [('g', 'git', None, _('use git extended diff format')), + ('U', 'unified', 3, _('number of lines of context to show')), ] + commands.walkopts, - _('hg qdiff [-I] [-X] [-g] [FILE]...')), + _('hg qdiff [-I] [-X] [-U NUM] [-g] [FILE]...')), "qdelete|qremove|qrm": (delete, [('k', 'keep', None, _('keep patch file')), diff -r 90e5c82a3859 -r 50a277e6ceae hgmerge --- a/hgmerge Mon Feb 18 19:20:22 2008 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,213 +0,0 @@ -#!/bin/sh -# -# hgmerge - default merge helper for Mercurial -# -# This tries to find a way to do three-way merge on the current system. -# The result ought to end up in $1. Script is run in root directory of -# repository. -# -# Environment variables set by Mercurial: -# HG_FILE name of file within repo -# HG_MY_NODE revision being merged -# HG_OTHER_NODE revision being merged - -set -e # bail out quickly on failure - -LOCAL="$1" -BASE="$2" -OTHER="$3" - -if [ -n "$VISUAL" ]; then - EDIT_PROG="$VISUAL" -elif [ -n "$EDITOR" ]; then - EDIT_PROG="$EDITOR" -else - EDIT_PROG="vi" -fi - -# find decent versions of our utilities, insisting on the GNU versions where we -# need to -MERGE="merge" -DIFF3="gdiff3" -DIFF="gdiff" -PATCH="gpatch" - -type "$MERGE" >/dev/null 2>&1 || MERGE= -type "$DIFF3" >/dev/null 2>&1 || DIFF3="diff3" -$DIFF3 --version >/dev/null 2>&1 || DIFF3= -type "$DIFF" >/dev/null 2>&1 || DIFF="diff" -type "$DIFF" >/dev/null 2>&1 || DIFF= -type "$PATCH" >/dev/null 2>&1 || PATCH="patch" -type "$PATCH" >/dev/null 2>&1 || PATCH= - -# find optional visual utilities -FILEMERGE="/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge" -KDIFF3="kdiff3" -TKDIFF="tkdiff" -MELD="meld" - -type "$FILEMERGE" >/dev/null 2>&1 || FILEMERGE= -type "$KDIFF3" >/dev/null 2>&1 || KDIFF3= -type "$TKDIFF" >/dev/null 2>&1 || TKDIFF= -type "$MELD" >/dev/null 2>&1 || MELD= - -# Hack for Solaris -TEST="/usr/bin/test" -type "$TEST" >/dev/null 2>&1 || TEST="/bin/test" -type "$TEST" >/dev/null 2>&1 || TEST="test" - -# random part of names -RAND="$RANDOM$RANDOM" - -# temporary directory for diff+patch merge -HGTMP="${TMPDIR-/tmp}/hgmerge.$RAND" - -# backup file -BACKUP="$LOCAL.orig.$RAND" - -# file used to test for file change -CHGTEST="$LOCAL.chg.$RAND" - -# put all your required cleanup here -cleanup() { - rm -f "$BACKUP" "$CHGTEST" - rm -rf "$HGTMP" -} - -# functions concerning program exit -success() { - cleanup - exit 0 -} - -failure() { - echo "merge failed" 1>&2 - mv "$BACKUP" "$LOCAL" - cleanup - exit 1 -} - -# Ask if the merge was successful -ask_if_merged() { - while true; do - echo "$LOCAL seems unchanged." - echo "Was the merge successful? [y/n]" - read answer - case "$answer" in - y*|Y*) success;; - n*|N*) failure;; - esac - done -} - -# Check if conflict markers are present and ask if the merge was successful -conflicts_or_success() { - while egrep '^(<<<<<<< .*|=======|>>>>>>> .*)$' "$LOCAL" >/dev/null; do - echo "$LOCAL contains conflict markers." - echo "Keep this version? [y/n]" - read answer - case "$answer" in - y*|Y*) success;; - n*|N*) failure;; - esac - done - success -} - -# Clean up when interrupted -trap "failure" 1 2 3 6 15 # HUP INT QUIT ABRT TERM - -# Back up our file (and try hard to keep the mtime unchanged) -mv "$LOCAL" "$BACKUP" -cp "$BACKUP" "$LOCAL" - -# Attempt to do a non-interactive merge -if [ -n "$MERGE" -o -n "$DIFF3" ]; then - if [ -n "$MERGE" ]; then - $MERGE "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && success - elif [ -n "$DIFF3" ]; then - $DIFF3 -m "$BACKUP" "$BASE" "$OTHER" > "$LOCAL" && success - fi - if [ $? -gt 1 ]; then - echo "automatic merge failed! Exiting." 1>&2 - failure - fi -fi - -# on MacOS X try FileMerge.app, shipped with Apple's developer tools -if [ -n "$FILEMERGE" ]; then - cp "$BACKUP" "$LOCAL" - cp "$BACKUP" "$CHGTEST" - # filemerge prefers the right by default - $FILEMERGE -left "$OTHER" -right "$LOCAL" -ancestor "$BASE" -merge "$LOCAL" - [ $? -ne 0 ] && echo "FileMerge failed to launch" && failure - $TEST "$LOCAL" -nt "$CHGTEST" && conflicts_or_success || ask_if_merged -fi - -if [ -n "$DISPLAY" ]; then - # try using kdiff3, which is fairly nice - if [ -n "$KDIFF3" ]; then - $KDIFF3 --auto "$BASE" "$BACKUP" "$OTHER" -o "$LOCAL" || failure - conflicts_or_success - fi - - # try using tkdiff, which is a bit less sophisticated - if [ -n "$TKDIFF" ]; then - $TKDIFF "$BACKUP" "$OTHER" -a "$BASE" -o "$LOCAL" || failure - conflicts_or_success - fi - - if [ -n "$MELD" ]; then - cp "$BACKUP" "$CHGTEST" - # protect our feet - meld allows us to save to the left file - cp "$BACKUP" "$LOCAL.tmp.$RAND" - # Meld doesn't have automatic merging, so to reduce intervention - # use the file with conflicts - $MELD "$LOCAL.tmp.$RAND" "$LOCAL" "$OTHER" || failure - # Also it doesn't return good error code - $TEST "$LOCAL" -nt "$CHGTEST" && conflicts_or_success || ask_if_merged - fi -fi - -# Attempt to do a merge with $EDIT_PROG -if [ -n "$MERGE" -o -n "$DIFF3" ]; then - echo "conflicts detected in $LOCAL" - cp "$BACKUP" "$CHGTEST" - case "$EDIT_PROG" in - "emacs") - $EDIT_PROG "$LOCAL" --eval '(condition-case nil (smerge-mode 1) (error nil))' || failure - ;; - *) - $EDIT_PROG "$LOCAL" || failure - ;; - esac - # Some editors do not return meaningful error codes - # Do not take any chances - $TEST "$LOCAL" -nt "$CHGTEST" && conflicts_or_success || ask_if_merged -fi - -# attempt to manually merge with diff and patch -if [ -n "$DIFF" -a -n "$PATCH" ]; then - - (umask 077 && mkdir "$HGTMP") || { - echo "Could not create temporary directory $HGTMP" 1>&2 - failure - } - - $DIFF -u "$BASE" "$OTHER" > "$HGTMP/diff" || : - if $PATCH "$LOCAL" < "$HGTMP/diff"; then - success - else - # If rejects are empty after using the editor, merge was ok - $EDIT_PROG "$LOCAL" "$LOCAL.rej" || failure - $TEST -s "$LOCAL.rej" || success - fi - failure -fi - -echo -echo "hgmerge: unable to find any merge utility!" -echo "supported programs:" -echo "merge, FileMerge, tkdiff, kdiff3, meld, diff+patch" -echo -failure diff -r 90e5c82a3859 -r 50a277e6ceae hgweb.cgi --- a/hgweb.cgi Mon Feb 18 19:20:22 2008 +0100 +++ b/hgweb.cgi Mon Feb 18 19:21:33 2008 +0100 @@ -9,9 +9,9 @@ # enable importing on demand to reduce startup time from mercurial import demandimport; demandimport.enable() -# send python tracebacks to the browser if an error occurs: -import cgitb -cgitb.enable() +# Uncomment to send python tracebacks to the browser if an error occurs: +#import cgitb +#cgitb.enable() # 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. diff -r 90e5c82a3859 -r 50a277e6ceae hgwebdir.cgi --- a/hgwebdir.cgi Mon Feb 18 19:20:22 2008 +0100 +++ b/hgwebdir.cgi Mon Feb 18 19:21:33 2008 +0100 @@ -9,9 +9,9 @@ # enable importing on demand to reduce startup time from mercurial import demandimport; demandimport.enable() -# send python tracebacks to the browser if an error occurs: -import cgitb -cgitb.enable() +# Uncomment to send python tracebacks to the browser if an error occurs: +#import cgitb +#cgitb.enable() # 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. diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/archival.py --- a/mercurial/archival.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/archival.py Mon Feb 18 19:21:33 2008 +0100 @@ -208,6 +208,8 @@ archiver.addfile(name, mode, islink, data) ctx = repo.changectx(node) + if kind not in archivers: + raise util.Abort(_("unknown archive type '%s'" % kind)) archiver = archivers[kind](dest, prefix, mtime or ctx.date()[0]) m = ctx.manifest() items = m.items() diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/bundlerepo.py --- a/mercurial/bundlerepo.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/bundlerepo.py Mon Feb 18 19:21:33 2008 +0100 @@ -154,8 +154,10 @@ def __init__(self, ui, path, bundlename): localrepo.localrepository.__init__(self, ui, path) - self._url = 'bundle:' + bundlename - if path: self._url += '+' + path + if path: + self._url = 'bundle:' + path + '+' + bundlename + else: + self._url = 'bundle:' + bundlename self.tempfile = None self.bundlefile = open(bundlename, "rb") diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/cmdutil.py --- a/mercurial/cmdutil.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/cmdutil.py Mon Feb 18 19:21:33 2008 +0100 @@ -1115,6 +1115,9 @@ def commit(ui, repo, commitfunc, pats, opts): '''commit the specified files or all outstanding changes''' + date = opts.get('date') + if date: + opts['date'] = util.parsedate(date) message = logmessage(opts) # extract addremove carefully -- this function can be called from a command @@ -1133,10 +1136,11 @@ continue if f not in files: rf = repo.wjoin(f) + rel = repo.pathto(f) try: mode = os.lstat(rf)[stat.ST_MODE] except OSError: - raise util.Abort(_("file %s not found!") % rf) + raise util.Abort(_("file %s not found!") % rel) if stat.S_ISDIR(mode): name = f + '/' if slist is None: @@ -1145,12 +1149,12 @@ i = bisect.bisect(slist, name) if i >= len(slist) or not slist[i].startswith(name): raise util.Abort(_("no match under directory %s!") - % rf) + % rel) elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)): raise util.Abort(_("can't commit %s: " - "unsupported file type!") % rf) + "unsupported file type!") % rel) elif f not in repo.dirstate: - raise util.Abort(_("file %s not tracked!") % rf) + raise util.Abort(_("file %s not tracked!") % rel) else: files = [] try: diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/commands.py --- a/mercurial/commands.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/commands.py Mon Feb 18 19:21:33 2008 +0100 @@ -78,7 +78,8 @@ detects as binary. With -a, annotate will generate an annotation anyway, probably with undesirable results. """ - getdate = util.cachefunc(lambda x: util.datestr(x[0].date())) + datefunc = ui.quiet and util.shortdate or util.datestr + getdate = util.cachefunc(lambda x: datefunc(x[0].date())) if not pats: raise util.Abort(_('at least one file name or pattern required')) @@ -195,6 +196,10 @@ if not rev: raise util.Abort(_("please specify a revision to backout")) + date = opts.get('date') + if date: + opts['date'] = util.parsedate(date) + cmdutil.bail_if_changed(repo) node = repo.lookup(rev) @@ -225,6 +230,7 @@ revert_opts['date'] = None revert_opts['all'] = True revert_opts['rev'] = hex(parent) + revert_opts['no_backup'] = None revert(ui, repo, **revert_opts) commit_opts = opts.copy() commit_opts['addremove'] = False @@ -339,6 +345,8 @@ Unless --force is specified, branch will not let you set a branch name that shadows an existing branch. + + Use the command 'hg update' to switch to an existing branch. """ if label: @@ -358,6 +366,8 @@ inactive. If active is specified, only show active branches. A branch is considered active if it contains unmerged heads. + + Use the command 'hg update' to switch to an existing branch. """ b = repo.branchtags() heads = dict.fromkeys(repo.heads(), 1) @@ -461,7 +471,10 @@ for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts, ctx.node()): fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs) - fp.write(ctx.filectx(abs).data()) + data = ctx.filectx(abs).data() + if opts.get('decode'): + data = repo.wwritedata(abs, data) + fp.write(data) err = 0 return err @@ -809,40 +822,6 @@ os.unlink(fa) os.unlink(fd) - # merge helper - ui.status(_("Checking merge helper...\n")) - cmd = (os.environ.get("HGMERGE") or ui.config("ui", "merge") - or "hgmerge") - cmdpath = util.find_exe(cmd) or util.find_exe(cmd.split()[0]) - if not cmdpath: - if cmd == 'hgmerge': - ui.write(_(" No merge helper set and can't find default" - " hgmerge script in PATH\n")) - ui.write(_(" (specify a merge helper in your .hgrc file)\n")) - else: - ui.write(_(" Can't find merge helper '%s' in PATH\n") % cmd) - ui.write(_(" (specify a merge helper in your .hgrc file)\n")) - problems += 1 - else: - # actually attempt a patch here - fa = writetemp("1\n2\n3\n4\n") - fl = writetemp("1\n2\n3\ninsert\n4\n") - fr = writetemp("begin\n1\n2\n3\n4\n") - r = util.system('%s "%s" "%s" "%s"' % (cmd, fl, fa, fr)) - if r: - ui.write(_(" Got unexpected merge error %d!\n") % r) - problems += 1 - m = file(fl).read() - if m != "begin\n1\n2\n3\ninsert\n4\n": - ui.write(_(" Got unexpected merge results!\n")) - ui.write(_(" (your merge helper may have the" - " wrong argument order)\n")) - ui.write(_(" Result: %r\n") % m) - problems += 1 - os.unlink(fa) - os.unlink(fl) - os.unlink(fr) - # editor ui.status(_("Checking commit editor...\n")) editor = ui.geteditor() @@ -992,7 +971,7 @@ try: regexp = re.compile(pattern, reflags) except Exception, inst: - ui.warn(_("grep: invalid match pattern: %s!\n") % inst) + ui.warn(_("grep: invalid match pattern: %s\n") % inst) return None sep, eol = ':', '\n' if opts['print0']: @@ -1054,6 +1033,7 @@ prev = {} def display(fn, rev, states, prevstates): + datefunc = ui.quiet and util.shortdate or util.datestr found = False filerevmatches = {} r = prev.get(fn, -1) @@ -1069,6 +1049,8 @@ cols.append(change) if opts['user']: cols.append(ui.shortuser(get(r)[1])) + if opts.get('date'): + cols.append(datefunc(get(r)[2])) if opts['files_with_matches']: c = (fn, r) if c in filerevmatches: @@ -1462,6 +1444,10 @@ """ patches = (patch1,) + patches + date = opts.get('date') + if date: + opts['date'] = util.parsedate(date) + if opts.get('exact') or not opts['force']: cmdutil.bail_if_changed(repo) @@ -1536,6 +1522,9 @@ repo.rollback() raise util.Abort(_('patch is damaged' ' or loses information')) + # Force a dirstate write so that the next transaction + # backups an up-do-date file. + repo.dirstate.write() finally: os.unlink(tmpname) finally: @@ -1739,6 +1728,8 @@ if opts["date"]: df = util.matchdate(opts["date"]) + only_branches = opts['only_branch'] + displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn) for st, rev, fns in changeiter: if st == 'add': @@ -1750,6 +1741,11 @@ if opts['only_merges'] and len(parents) != 2: continue + if only_branches: + revbranch = get(rev)[5]['branch'] + if revbranch not in only_branches: + continue + if df: changes = get(rev) if not df(changes[2][0]): @@ -2223,16 +2219,16 @@ # but not other. names = {} - target_only = {} wlock = repo.wlock() try: # walk dirstate. + files = [] for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, badmatch=mf.has_key): names[abs] = (rel, exact) - if src == 'b': - target_only[abs] = True + if src != 'b': + files.append(abs) # walk target manifest. @@ -2250,10 +2246,9 @@ if abs in names or src == 'b': continue names[abs] = (rel, exact) - target_only[abs] = True - - changes = repo.status(match=names.has_key)[:5] - modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) + + changes = repo.status(files=files, match=names.has_key)[:4] + modified, added, removed, deleted = map(dict.fromkeys, changes) # if f is a rename, also revert the source cwd = repo.getcwd() @@ -2263,12 +2258,15 @@ removed[src] = None names[src] = (repo.pathto(src, cwd), True) + def removeforget(abs): + if repo.dirstate[abs] == 'a': + return _('forgetting %s\n') + return _('removing %s\n') + revert = ([], _('reverting %s\n')) add = ([], _('adding %s\n')) - remove = ([], _('removing %s\n')) - forget = ([], _('forgetting %s\n')) + remove = ([], removeforget) undelete = ([], _('undeleting %s\n')) - update = {} disptable = ( # dispatch table: @@ -2278,11 +2276,9 @@ # make backup if in target manifest # make backup if not in target manifest (modified, revert, remove, True, True), - (added, revert, forget, True, False), + (added, revert, remove, True, False), (removed, undelete, None, False, False), (deleted, revert, remove, False, False), - (unknown, add, None, True, False), - (target_only, add, None, False, False), ) entries = names.items() @@ -2293,7 +2289,6 @@ target = repo.wjoin(abs) def handle(xlist, dobackup): xlist[0].append(abs) - update[abs] = 1 if dobackup and not opts['no_backup'] and util.lexists(target): bakname = "%s.orig" % rel ui.note(_('saving current version of %s as %s\n') % @@ -2301,7 +2296,10 @@ if not opts.get('dry_run'): util.copyfile(target, bakname) if ui.verbose or not exact: - ui.status(xlist[1] % rel) + msg = xlist[1] + if not isinstance(msg, basestring): + msg = msg(abs) + ui.status(msg % rel) for table, hitlist, misslist, backuphit, backupmiss in disptable: if abs not in table: continue # file has changed in dirstate @@ -2309,10 +2307,14 @@ handle(hitlist, backuphit) elif misslist is not None: handle(misslist, backupmiss) - else: - if exact: ui.warn(_('file not managed: %s\n') % rel) break else: + if abs not in repo.dirstate: + if mfentry: + handle(add, True) + elif exact: + ui.warn(_('file not managed: %s\n') % rel) + continue # file has not changed in dirstate if node == parent: if exact: ui.warn(_('no changes needed to %s\n') % rel) @@ -2325,22 +2327,43 @@ if mfentry: # if version of file is same in parent and target # manifests, do nothing - if pmf[abs] != mfentry: + if (pmf[abs] != mfentry or + pmf.flags(abs) != mf.flags(abs)): handle(revert, False) else: handle(remove, False) if not opts.get('dry_run'): - for f in forget[0]: - repo.dirstate.forget(f) - r = hg.revert(repo, node, update.has_key) + def checkout(f): + fc = ctx[f] + repo.wwrite(f, fc.data(), fc.fileflags()) + + audit_path = util.path_auditor(repo.root) + for f in remove[0]: + if repo.dirstate[f] == 'a': + repo.dirstate.forget(f) + continue + audit_path(f) + try: + util.unlink(repo.wjoin(f)) + except OSError: + pass + repo.dirstate.remove(f) + + for f in revert[0]: + checkout(f) + for f in add[0]: + checkout(f) repo.dirstate.add(f) + + normal = repo.dirstate.normallookup + if node == parent and p2 == nullid: + normal = repo.dirstate.normal for f in undelete[0]: - repo.dirstate.normal(f) - for f in remove[0]: - repo.dirstate.remove(f) - return r + checkout(f) + normal(f) + finally: del wlock @@ -2441,8 +2464,10 @@ """show changed files in the working directory Show status of files in the repository. If names are given, only - files that match are shown. Files that are clean or ignored, are - not listed unless -c (clean), -i (ignored) or -A is given. + files that match are shown. Files that are clean or ignored or + source of a copy/move operation, are not listed unless -c (clean), + -i (ignored), -C (copies) or -A is given. Unless options described + with "show only ..." are given, the options -mardu are used. NOTE: status may appear to disagree with diff if permissions have changed or a merge has occurred. The standard diff format does not @@ -2459,7 +2484,7 @@ C = clean ! = deleted, but still tracked ? = not tracked - I = ignored (not shown by default) + I = ignored = the previous added file was copied from here """ @@ -2727,8 +2752,8 @@ [('r', 'rev', '', _('annotate the specified revision')), ('f', 'follow', None, _('follow file copies and renames')), ('a', 'text', None, _('treat all files as text')), - ('u', 'user', None, _('list the author')), - ('d', 'date', None, _('list the date')), + ('u', 'user', None, _('list the author (long with -v)')), + ('d', 'date', None, _('list the date (short with -q)')), ('n', 'number', None, _('list the revision number (default)')), ('c', 'changeset', None, _('list the changeset')), ('l', 'line-number', None, @@ -2783,6 +2808,7 @@ (cat, [('o', 'output', '', _('print output to file with formatted name')), ('r', 'rev', '', _('print the given revision')), + ('', 'decode', None, _('apply any matching decode filter')), ] + walkopts, _('hg cat [OPTION]... FILE...')), "^clone": @@ -2857,6 +2883,8 @@ _('ignore changes in the amount of white space')), ('B', 'ignore-blank-lines', None, _('ignore changes whose lines are all blank')), + ('U', 'unified', 3, + _('number of lines of context to show')) ] + walkopts, _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')), "^export": @@ -2878,7 +2906,8 @@ _('print only filenames and revs that match')), ('n', 'line-number', None, _('print matching line numbers')), ('r', 'rev', [], _('search in given revision range')), - ('u', 'user', None, _('print user who committed change')), + ('u', 'user', None, _('list the author (long with -v)')), + ('d', 'date', None, _('list the date (short with -q)')), ] + walkopts, _('hg grep [OPTION]... PATTERN [FILE]...')), "heads": @@ -2953,6 +2982,8 @@ ('M', 'no-merges', None, _('do not show merges')), ('', 'style', '', _('display using template map file')), ('m', 'only-merges', None, _('show only merges')), + ('b', 'only-branch', [], + _('show only changesets within the given named branch')), ('p', 'patch', None, _('show patch')), ('P', 'prune', [], _('do not display revision or any of its ancestors')), ('', 'template', '', _('display with template')), diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/dirstate.py --- a/mercurial/dirstate.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/dirstate.py Mon Feb 18 19:21:33 2008 +0100 @@ -197,7 +197,8 @@ def _incpathcheck(self, f): if '\r' in f or '\n' in f: - raise util.Abort(_("'\\n' and '\\r' disallowed in filenames")) + raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r") + % f) # shadows if f in self._dirs: raise util.Abort(_('directory %r already in dirstate') % f) @@ -286,7 +287,7 @@ self._changepath(f, '?') del self._map[f] except KeyError: - self._ui.warn(_("not in dirstate: %s!\n") % f) + self._ui.warn(_("not in dirstate: %s\n") % f) def clear(self): self._map = {} @@ -369,6 +370,14 @@ % (self.pathto(f), kind)) return False + def _dirignore(self, f): + if self._ignore(f): + return True + for c in strutil.findall(f, '/'): + if self._ignore(f[:c]): + return True + return False + def walk(self, files=None, match=util.always, badmatch=None): # filter out the stat for src, f, st in self.statwalk(files, match, badmatch=badmatch): @@ -404,9 +413,11 @@ return match(file_) ignore = self._ignore + dirignore = self._dirignore if ignored: imatch = match ignore = util.never + dirignore = util.never # self._root may end with a path separator when self._root == '/' common_prefix_len = len(self._root) @@ -492,8 +503,9 @@ yield 'b', ff, None continue if s_isdir(st.st_mode): - for f, src, st in findfiles(f): - yield src, f, st + if not dirignore(nf): + for f, src, st in findfiles(f): + yield src, f, st else: if nf in known: continue @@ -519,6 +531,7 @@ lookup, modified, added, unknown, ignored = [], [], [], [], [] removed, deleted, clean = [], [], [] + files = files or [] _join = self._join lstat = os.lstat cmap = self._copymap @@ -536,8 +549,9 @@ if fn in dmap: type_, mode, size, time, foo = dmap[fn] else: - if list_ignored and self._ignore(fn): - iadd(fn) + if (list_ignored or fn in files) and self._dirignore(fn): + if list_ignored: + iadd(fn) else: uadd(fn) continue @@ -555,7 +569,7 @@ nonexistent = False # XXX: what to do with file no longer present in the fs # who are not removed in the dirstate ? - if nonexistent and type_ in "nm": + if nonexistent and type_ in "nma": dadd(fn) continue # check the common case first diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/dispatch.py --- a/mercurial/dispatch.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/dispatch.py Mon Feb 18 19:21:33 2008 +0100 @@ -340,9 +340,9 @@ try: repo = hg.repository(ui, path=path) ui = repo.ui - ui.setconfig("bundle", "mainreporoot", repo.root) if not repo.local(): raise util.Abort(_("repository '%s' is not local") % path) + ui.setconfig("bundle", "mainreporoot", repo.root) except hg.RepoError: if cmd not in commands.optionalrepo.split(): if not path: diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/filemerge.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial/filemerge.py Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,217 @@ +# filemerge.py - file-level merge handling for Mercurial +# +# Copyright 2006, 2007, 2008 Matt Mackall +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +from node import * +from i18n import _ +import util, os, tempfile, context, simplemerge, re, filecmp + +def _toolstr(ui, tool, part, default=""): + return ui.config("merge-tools", tool + "." + part, default) + +def _toolbool(ui, tool, part, default=False): + return ui.configbool("merge-tools", tool + "." + part, default) + +def _findtool(ui, tool): + k = _toolstr(ui, tool, "regkey") + if k: + p = util.lookup_reg(k, _toolstr(ui, tool, "regname")) + if p: + p = util.find_exe(p + _toolstr(ui, tool, "regappend")) + if p: + return p + return util.find_exe(_toolstr(ui, tool, "executable", tool)) + +def _picktool(repo, ui, path, binary, symlink): + def check(tool, pat, symlink, binary): + tmsg = tool + if pat: + tmsg += " specified for " + pat + if pat and not _findtool(ui, tool): # skip search if not matching + ui.warn(_("couldn't find merge tool %s\n") % tmsg) + elif symlink and not _toolbool(ui, tool, "symlink"): + ui.warn(_("tool %s can't handle symlinks\n") % tmsg) + elif binary and not _toolbool(ui, tool, "binary"): + ui.warn(_("tool %s can't handle binary\n") % tmsg) + elif not util.gui() and _toolbool(ui, tool, "gui"): + ui.warn(_("tool %s requires a GUI\n") % tmsg) + else: + return True + return False + + # HGMERGE takes precedence + hgmerge = os.environ.get("HGMERGE") + if hgmerge: + return (hgmerge, hgmerge) + + # then patterns + for pat, tool in ui.configitems("merge-patterns"): + mf = util.matcher(repo.root, "", [pat], [], [])[1] + if mf(path) and check(tool, pat, symlink, False): + toolpath = _findtool(ui, tool) + return (tool, '"' + toolpath + '"') + + # then merge tools + tools = {} + for k,v in ui.configitems("merge-tools"): + t = k.split('.')[0] + if t not in tools: + tools[t] = int(_toolstr(ui, t, "priority", "0")) + names = tools.keys() + tools = [(-p,t) for t,p in tools.items()] + tools.sort() + uimerge = ui.config("ui", "merge") + if uimerge: + if uimerge not in names: + return (uimerge, uimerge) + tools.insert(0, (None, uimerge)) # highest priority + tools.append((None, "hgmerge")) # the old default, if found + for p,t in tools: + toolpath = _findtool(ui, t) + if toolpath and check(t, None, symlink, binary): + return (t, '"' + toolpath + '"') + # internal merge as last resort + return (not (symlink or binary) and "internal:merge" or None, None) + +def _eoltype(data): + "Guess the EOL type of a file" + if '\0' in data: # binary + return None + if '\r\n' in data: # Windows + return '\r\n' + if '\r' in data: # Old Mac + return '\r' + if '\n' in data: # UNIX + return '\n' + return None # unknown + +def _matcheol(file, origfile): + "Convert EOL markers in a file to match origfile" + tostyle = _eoltype(open(origfile, "rb").read()) + if tostyle: + data = open(file, "rb").read() + style = _eoltype(data) + if style: + newdata = data.replace(style, tostyle) + if newdata != data: + open(file, "wb").write(newdata) + +def filemerge(repo, fw, fd, fo, wctx, mctx): + """perform a 3-way merge in the working directory + + fw = original filename in the working directory + fd = destination filename in the working directory + fo = filename in other parent + wctx, mctx = working and merge changecontexts + """ + + def temp(prefix, ctx): + pre = "%s~%s." % (os.path.basename(ctx.path()), prefix) + (fd, name) = tempfile.mkstemp(prefix=pre) + data = repo.wwritedata(ctx.path(), ctx.data()) + f = os.fdopen(fd, "wb") + f.write(data) + f.close() + return name + + def isbin(ctx): + try: + return util.binary(ctx.data()) + except IOError: + return False + + fco = mctx.filectx(fo) + if not fco.cmp(wctx.filectx(fd).data()): # files identical? + return None + + ui = repo.ui + fcm = wctx.filectx(fw) + fca = fcm.ancestor(fco) or repo.filectx(fw, fileid=nullrev) + binary = isbin(fcm) or isbin(fco) or isbin(fca) + symlink = fcm.islink() or fco.islink() + tool, toolpath = _picktool(repo, ui, fw, binary, symlink) + ui.debug(_("picked tool '%s' for %s (binary %s symlink %s)\n") % + (tool, fw, binary, symlink)) + + if not tool: + tool = "internal:local" + if ui.prompt(_(" no tool found to merge %s\n" + "keep (l)ocal or take (o)ther?") % fw, + _("[lo]"), _("l")) != _("l"): + tool = "internal:other" + if tool == "internal:local": + return 0 + if tool == "internal:other": + repo.wwrite(fd, fco.data(), fco.fileflags()) + return 0 + if tool == "internal:fail": + return 1 + + # do the actual merge + a = repo.wjoin(fd) + b = temp("base", fca) + c = temp("other", fco) + out = "" + back = a + ".orig" + util.copyfile(a, back) + + if fw != fo: + repo.ui.status(_("merging %s and %s\n") % (fw, fo)) + else: + repo.ui.status(_("merging %s\n") % fw) + repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcm, fco, fca)) + + # do we attempt to simplemerge first? + if _toolbool(ui, tool, "premerge", not (binary or symlink)): + r = simplemerge.simplemerge(a, b, c, quiet=True) + if not r: + ui.debug(_(" premerge successful\n")) + os.unlink(back) + os.unlink(b) + os.unlink(c) + return 0 + util.copyfile(back, a) # restore from backup and try again + + env = dict(HG_FILE=fd, + HG_MY_NODE=str(wctx.parents()[0]), + HG_OTHER_NODE=str(mctx), + HG_MY_ISLINK=fcm.islink(), + HG_OTHER_ISLINK=fco.islink(), + HG_BASE_ISLINK=fca.islink()) + + if tool == "internal:merge": + r = simplemerge.simplemerge(a, b, c, label=['local', 'other']) + else: + args = _toolstr(ui, tool, "args", '$local $base $other') + if "$output" in args: + out, a = a, back # read input from backup, write to original + replace = dict(local=a, base=b, other=c, output=out) + args = re.sub("\$(local|base|other|output)", + lambda x: '"%s"' % replace[x.group()[1:]], args) + r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env) + + if not r and _toolbool(ui, tool, "checkconflicts"): + if re.match("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcm.data()): + r = 1 + + if not r and _toolbool(ui, tool, "checkchanged"): + if filecmp.cmp(repo.wjoin(fd), back): + if ui.prompt(_(" output file %s appears unchanged\n" + "was merge successful (yn)?") % fd, + _("[yn]"), _("n")) != _("y"): + r = 1 + + if _toolbool(ui, tool, "fixeol"): + _matcheol(repo.wjoin(fd), back) + + if r: + repo.ui.warn(_("merging %s failed!\n") % fd) + else: + os.unlink(back) + + os.unlink(b) + os.unlink(c) + return r diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/help.py --- a/mercurial/help.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/help.py Mon Feb 18 19:21:33 2008 +0100 @@ -66,9 +66,6 @@ will be executed with three arguments: local file, remote file, ancestor file. - The default program is "hgmerge", which is a shell script provided - by Mercurial with some sensible defaults. - (deprecated, use .hgrc) HGRCPATH:: @@ -97,11 +94,11 @@ This is the name of the editor to use when committing. See EDITOR. EDITOR:: - Sometimes Mercurial needs to open a text file in an editor for a user - to modify, for example when writing commit messages or when using the - hgmerge script. The editor it uses is determined by looking at the - environment variables HGEDITOR, VISUAL and EDITOR, in that order. The - first non-empty one is chosen. If all of them are empty, the editor + Sometimes Mercurial needs to open a text file in an editor + for a user to modify, for example when writing commit messages. + The editor it uses is determined by looking at the environment + variables HGEDITOR, VISUAL and EDITOR, in that order. The first + non-empty one is chosen. If all of them are empty, the editor defaults to 'vi'. PYTHONPATH:: diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/hg.py --- a/mercurial/hg.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/hg.py Mon Feb 18 19:21:33 2008 +0100 @@ -105,14 +105,14 @@ destination is local repository """ - origsource = source - source, rev, checkout = parseurl(ui.expandpath(source), rev) - if isinstance(source, str): + origsource = ui.expandpath(source) + source, rev, checkout = parseurl(origsource, rev) src_repo = repository(ui, source) else: src_repo = source - source = src_repo.url() + origsource = source = src_repo.url() + checkout = None if dest is None: dest = defaultdest(source) diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/hgweb/common.py --- a/mercurial/hgweb/common.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/hgweb/common.py Mon Feb 18 19:21:33 2008 +0100 @@ -101,6 +101,12 @@ parity = 1 - parity count = 0 +def countgen(start=0, step=1): + """count forever -- useful for line numbers""" + while True: + yield start + start += step + def get_contact(config): """Return repo contact information or empty string. diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/hgweb/hgweb_mod.py Mon Feb 18 19:21:33 2008 +0100 @@ -10,7 +10,8 @@ from mercurial.node import * from mercurial import mdiff, ui, hg, util, archival, patch, hook from mercurial import revlog, templater, templatefilters -from common import ErrorResponse, get_mtime, style_map, paritygen, get_contact +from common import get_mtime, style_map, paritygen, countgen, get_contact +from common import ErrorResponse from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR from request import wsgirequest import webcommands, protocol @@ -371,16 +372,26 @@ file=f, filenode=hex(fn or nullid)) + blockcount = countgen() def prettyprintlines(diff): - for l in diff.splitlines(1): + blockno = blockcount.next() + for lineno, l in enumerate(diff.splitlines(1)): + if blockno == 0: + lineno = lineno + 1 + else: + lineno = "%d.%d" % (blockno, lineno + 1) if l.startswith('+'): - yield tmpl("difflineplus", line=l) + ltype = "difflineplus" elif l.startswith('-'): - yield tmpl("difflineminus", line=l) + ltype = "difflineminus" elif l.startswith('@'): - yield tmpl("difflineat", line=l) + ltype = "difflineat" else: - yield tmpl("diffline", line=l) + ltype = "diffline" + yield tmpl(ltype, + line=l, + lineid="l%s" % lineno, + linenumber="% 8s" % lineno) r = self.repo c1 = r.changectx(node1) @@ -466,7 +477,7 @@ def revgen(): for i in xrange(cl.count() - 1, 0, -100): l = [] - for j in xrange(max(0, i - 100), i): + for j in xrange(max(0, i - 100), i + 1): ctx = self.repo.changectx(j) l.append(ctx) l.reverse() @@ -596,9 +607,10 @@ text = '(binary:%s)' % mt def lines(): - for l, t in enumerate(text.splitlines(1)): + for lineno, t in enumerate(text.splitlines(1)): yield {"line": t, - "linenumber": "% 6d" % (l + 1), + "lineid": "l%d" % (lineno + 1), + "linenumber": "% 6d" % (lineno + 1), "parity": parity.next()} return tmpl("filerevision", @@ -623,7 +635,8 @@ def annotate(**map): last = None - for f, l in fctx.annotate(follow=True): + lines = enumerate(fctx.annotate(follow=True, linenumber=True)) + for lineno, ((f, targetline), l) in lines: fnode = f.filenode() name = self.repo.ui.shortuser(f.user()) @@ -635,7 +648,10 @@ "rev": f.rev(), "author": name, "file": f.path(), - "line": l} + "targetline": targetline, + "line": l, + "lineid": "l%d" % (lineno + 1), + "linenumber": "% 6d" % (lineno + 1)} return tmpl("fileannotate", file=f, diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/hgweb/hgwebdir_mod.py --- a/mercurial/hgweb/hgwebdir_mod.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/hgweb/hgwebdir_mod.py Mon Feb 18 19:21:33 2008 +0100 @@ -177,7 +177,7 @@ if u.configbool("web", "hidden", untrusted=True): continue - parts = [req.env['PATH_INFO'].strip('/'), name] + parts = [req.env['PATH_INFO'].rstrip('/'), name] if req.env['SCRIPT_NAME']: parts.insert(0, req.env['SCRIPT_NAME']) url = ('/'.join(parts).replace("//", "/")) + '/' diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/hgweb/request.py --- a/mercurial/hgweb/request.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/hgweb/request.py Mon Feb 18 19:21:33 2008 +0100 @@ -85,8 +85,10 @@ if type is not None: headers.append(('Content-Type', type)) if filename: - headers.append(('Content-Disposition', 'inline; filename=%s' % - filename)) + filename = (filename.split('/')[-1] + .replace('\\', '\\\\').replace('"', '\\"')) + headers.append(('Content-Disposition', + 'inline; filename="%s"' % filename)) if length: headers.append(('Content-Length', str(length))) self.header(headers) diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/httprepo.py --- a/mercurial/httprepo.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/httprepo.py Mon Feb 18 19:21:33 2008 +0100 @@ -103,10 +103,13 @@ # must be able to send big bundle as stream. send = _gen_sendfile(keepalive.HTTPConnection) -class basehttphandler(keepalive.HTTPHandler): +class httphandler(keepalive.HTTPHandler): def http_open(self, req): return self.do_open(httpconnection, req) + def __del__(self): + self.close_all() + has_https = hasattr(urllib2, 'HTTPSHandler') if has_https: class httpsconnection(httplib.HTTPSConnection): @@ -114,12 +117,9 @@ # must be able to send big bundle as stream. send = _gen_sendfile(httplib.HTTPSConnection) - class httphandler(basehttphandler, urllib2.HTTPSHandler): + class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler): def https_open(self, req): return self.do_open(httpsconnection, req) -else: - class httphandler(basehttphandler): - pass # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if # it doesn't know about the auth type requested. This can happen if @@ -203,8 +203,9 @@ proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') # XXX proxyauthinfo = None - self.handler = httphandler() - handlers = [self.handler] + handlers = [httphandler()] + if has_https: + handlers.append(httpshandler()) if proxyurl: # proxy can be proper url or host[:port] @@ -270,11 +271,6 @@ opener.addheaders = [('User-agent', 'mercurial/proto-1.0')] urllib2.install_opener(opener) - def __del__(self): - if self.handler: - self.handler.close_all() - self.handler = None - def url(self): return self.path diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/keepalive.py --- a/mercurial/keepalive.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/keepalive.py Mon Feb 18 19:21:33 2008 +0100 @@ -175,7 +175,7 @@ else: return dict(self._hostmap) -class HTTPHandler(urllib2.HTTPHandler): +class KeepAliveHandler: def __init__(self): self._cm = ConnectionManager() @@ -314,6 +314,9 @@ except socket.error, err: # XXX what error? raise urllib2.URLError(err) +class HTTPHandler(KeepAliveHandler, urllib2.HTTPHandler): + pass + class HTTPResponse(httplib.HTTPResponse): # we need to subclass HTTPResponse in order to # 1) add readline() and readlines() methods diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/localrepo.py --- a/mercurial/localrepo.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/localrepo.py Mon Feb 18 19:21:33 2008 +0100 @@ -68,8 +68,21 @@ self.encodefn = lambda x: x self.decodefn = lambda x: x self.spath = self.path - self.sopener = util.encodedopener(util.opener(self.spath), - self.encodefn) + + try: + # files in .hg/ will be created using this mode + mode = os.stat(self.spath).st_mode + # avoid some useless chmods + if (0777 & ~util._umask) == (0777 & mode): + mode = None + except OSError: + mode = None + + self._createmode = mode + self.opener.createmode = mode + sopener = util.opener(self.spath) + sopener.createmode = mode + self.sopener = util.encodedopener(sopener, self.encodefn) self.ui = ui.ui(parentui=parentui) try: @@ -81,6 +94,8 @@ self.tagscache = None self._tagstypecache = None self.branchcache = None + self._ubranchcache = None # UTF-8 version of branchcache + self._branchcachetip = None self.nodetagscache = None self.filterpats = {} self._datafilters = {} @@ -120,6 +135,7 @@ self.hook('pretag', throw=True, node=hex(node), tag=name, local=local) def writetag(fp, name, munge, prevtags): + fp.seek(0, 2) if prevtags and prevtags[-1] != '\n': fp.write('\n') fp.write('%s %s\n' % (hex(node), munge and munge(name) or name)) @@ -186,6 +202,7 @@ date: date tuple to use if committing''' + date = util.parsedate(date) for x in self.status()[:5]: if '.hgtags' in x: raise util.Abort(_('working copy of .hgtags is changed ' @@ -330,9 +347,7 @@ self.nodetagscache.setdefault(n, []).append(t) return self.nodetagscache.get(node, []) - def _branchtags(self): - partial, last, lrev = self._readbranchcache() - + def _branchtags(self, partial, lrev): tiprev = self.changelog.count() - 1 if lrev != tiprev: self._updatebranchcache(partial, lrev+1, tiprev+1) @@ -341,16 +356,29 @@ return partial def branchtags(self): - if self.branchcache is not None: + tip = self.changelog.tip() + if self.branchcache is not None and self._branchcachetip == tip: return self.branchcache - self.branchcache = {} # avoid recursion in changectx - partial = self._branchtags() + oldtip = self._branchcachetip + self._branchcachetip = tip + if self.branchcache is None: + self.branchcache = {} # avoid recursion in changectx + else: + self.branchcache.clear() # keep using the same dict + if oldtip is None or oldtip not in self.changelog.nodemap: + partial, last, lrev = self._readbranchcache() + else: + lrev = self.changelog.rev(oldtip) + partial = self._ubranchcache + + self._branchtags(partial, lrev) # the branch cache is stored on disk as UTF-8, but in the local # charset internally for k, v in partial.items(): self.branchcache[util.tolocal(k)] = v + self._ubranchcache = partial return self.branchcache def _readbranchcache(self): @@ -368,7 +396,7 @@ if not (lrev < self.changelog.count() and self.changelog.node(lrev) == last): # sanity check # invalidate the cache - raise ValueError('Invalid branch cache: unknown tip') + raise ValueError('invalidating branch cache (tip differs)') for l in lines: if not l: continue node, label = l.split(" ", 1) @@ -487,9 +515,11 @@ for pat, cmd in self.ui.configitems(filter): mf = util.matcher(self.root, "", [pat], [], [])[1] fn = None + params = cmd for name, filterfn in self._datafilters.iteritems(): if cmd.startswith(name): fn = filterfn + params = cmd[len(name):].lstrip() break if not fn: fn = lambda s, c, **kwargs: util.filter(s, c) @@ -497,7 +527,7 @@ if not inspect.getargspec(fn)[2]: oldfn = fn fn = lambda s, c, **kwargs: oldfn(s, c) - l.append((mf, fn, cmd)) + l.append((mf, fn, params)) self.filterpats[filter] = l for mf, fn, cmd in self.filterpats[filter]: @@ -550,8 +580,9 @@ (self.join("journal.dirstate"), self.join("undo.dirstate")), (self.join("journal.branch"), self.join("undo.branch"))] tr = transaction.transaction(self.ui.warn, self.sopener, - self.sjoin("journal"), - aftertrans(renames)) + self.sjoin("journal"), + aftertrans(renames), + self._createmode) self._transref = weakref.ref(tr) return tr @@ -578,8 +609,13 @@ self.ui.status(_("rolling back last transaction\n")) transaction.rollback(self.sopener, self.sjoin("undo")) util.rename(self.join("undo.dirstate"), self.join("dirstate")) - branch = self.opener("undo.branch").read() - self.dirstate.setbranch(branch) + try: + branch = self.opener("undo.branch").read() + self.dirstate.setbranch(branch) + except IOError: + self.ui.warn(_("Named branch could not be reset, " + "current branch still is: %s\n") + % util.tolocal(self.dirstate.branch())) self.invalidate() self.dirstate.invalidate() else: @@ -594,6 +630,9 @@ self.tagscache = None self._tagstypecache = None self.nodetagscache = None + self.branchcache = None + self._ubranchcache = None + self._branchcachetip = None def _lock(self, lockname, wait, releasefn, acquirefn, desc): try: @@ -860,8 +899,8 @@ parent2=xp2) tr.close() - if self.branchcache and "branch" in extra: - self.branchcache[util.tolocal(extra["branch"])] = n + if self.branchcache: + self.branchtags() if use_dirstate or update_dirstate: self.dirstate.setparents(n) @@ -1484,7 +1523,7 @@ self.ui.warn(_("abort: push creates new remote branches!\n")) self.ui.status(_("(did you forget to merge?" " use push -f to force)\n")) - return None, 1 + return None, 0 elif inc: self.ui.warn(_("note: unsynced remote changes!\n")) @@ -1981,6 +2020,9 @@ del tr if changesets > 0: + # forcefully update the on-disk branch cache + self.ui.debug(_("updating the branch cache\n")) + self.branchtags() self.hook("changegroup", node=hex(self.changelog.node(cor+1)), source=srctype, url=url) diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/merge.py --- a/mercurial/merge.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/merge.py Mon Feb 18 19:21:33 2008 +0100 @@ -7,62 +7,7 @@ from node import * from i18n import _ -import errno, util, os, tempfile, context, heapq - -def filemerge(repo, fw, fd, fo, wctx, mctx): - """perform a 3-way merge in the working directory - - fw = original filename in the working directory - fd = destination filename in the working directory - fo = filename in other parent - wctx, mctx = working and merge changecontexts - """ - - def temp(prefix, ctx): - pre = "%s~%s." % (os.path.basename(ctx.path()), prefix) - (fd, name) = tempfile.mkstemp(prefix=pre) - data = repo.wwritedata(ctx.path(), ctx.data()) - f = os.fdopen(fd, "wb") - f.write(data) - f.close() - return name - - fcm = wctx.filectx(fw) - fcmdata = wctx.filectx(fd).data() - fco = mctx.filectx(fo) - - if not fco.cmp(fcmdata): # files identical? - return None - - fca = fcm.ancestor(fco) - if not fca: - fca = repo.filectx(fw, fileid=nullrev) - a = repo.wjoin(fd) - b = temp("base", fca) - c = temp("other", fco) - - if fw != fo: - repo.ui.status(_("merging %s and %s\n") % (fw, fo)) - else: - repo.ui.status(_("merging %s\n") % fw) - - repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcm, fco, fca)) - - cmd = (os.environ.get("HGMERGE") or repo.ui.config("ui", "merge") - or "hgmerge") - r = util.system('%s "%s" "%s" "%s"' % (cmd, a, b, c), cwd=repo.root, - environ={'HG_FILE': fd, - 'HG_MY_NODE': str(wctx.parents()[0]), - 'HG_OTHER_NODE': str(mctx), - 'HG_MY_ISLINK': fcm.islink(), - 'HG_OTHER_ISLINK': fco.islink(), - 'HG_BASE_ISLINK': fca.islink(),}) - if r: - repo.ui.warn(_("merging %s failed!\n") % fd) - - os.unlink(b) - os.unlink(c) - return r +import errno, util, os, heapq, filemerge def checkunknown(wctx, mctx): "check for collisions between unknown files and files in mctx" @@ -514,7 +459,7 @@ removed += 1 elif m == "m": # merge f2, fd, flags, move = a[2:] - r = filemerge(repo, f, fd, f2, wctx, mctx) + r = filemerge.filemerge(repo, f, fd, f2, wctx, mctx) if r > 0: unresolved += 1 else: diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/patch.py --- a/mercurial/patch.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/patch.py Mon Feb 18 19:21:33 2008 +0100 @@ -1056,7 +1056,8 @@ showfunc=get('show_function', 'showfunc'), ignorews=get('ignore_all_space', 'ignorews'), ignorewsamount=get('ignore_space_change', 'ignorewsamount'), - ignoreblanklines=get('ignore_blank_lines', 'ignoreblanklines')) + ignoreblanklines=get('ignore_blank_lines', 'ignoreblanklines'), + context=get('unified')) def updatedir(ui, repo, patches): '''Update dirstate after patch application according to metadata''' diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/simplemerge.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial/simplemerge.py Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,456 @@ +#!/usr/bin/env python +# Copyright (C) 2004, 2005 Canonical Ltd +# +# This program 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# mbp: "you know that thing where cvs gives you conflict markers?" +# s: "i hate that." + +from i18n import _ +import util, mdiff, fancyopts, sys, os + +class CantReprocessAndShowBase(Exception): + pass + +def warn(message): + sys.stdout.flush() + sys.stderr.write(message) + sys.stderr.flush() + +def intersect(ra, rb): + """Given two ranges return the range where they intersect or None. + + >>> intersect((0, 10), (0, 6)) + (0, 6) + >>> intersect((0, 10), (5, 15)) + (5, 10) + >>> intersect((0, 10), (10, 15)) + >>> intersect((0, 9), (10, 15)) + >>> intersect((0, 9), (7, 15)) + (7, 9) + """ + assert ra[0] <= ra[1] + assert rb[0] <= rb[1] + + sa = max(ra[0], rb[0]) + sb = min(ra[1], rb[1]) + if sa < sb: + return sa, sb + else: + return None + +def compare_range(a, astart, aend, b, bstart, bend): + """Compare a[astart:aend] == b[bstart:bend], without slicing. + """ + if (aend-astart) != (bend-bstart): + return False + for ia, ib in zip(xrange(astart, aend), xrange(bstart, bend)): + if a[ia] != b[ib]: + return False + else: + return True + +class Merge3Text(object): + """3-way merge of texts. + + Given strings BASE, OTHER, THIS, tries to produce a combined text + incorporating the changes from both BASE->OTHER and BASE->THIS.""" + def __init__(self, basetext, atext, btext, base=None, a=None, b=None): + self.basetext = basetext + self.atext = atext + self.btext = btext + if base is None: + base = mdiff.splitnewlines(basetext) + if a is None: + a = mdiff.splitnewlines(atext) + if b is None: + b = mdiff.splitnewlines(btext) + self.base = base + self.a = a + self.b = b + + def merge_lines(self, + name_a=None, + name_b=None, + name_base=None, + start_marker='<<<<<<<', + mid_marker='=======', + end_marker='>>>>>>>', + base_marker=None, + reprocess=False): + """Return merge in cvs-like form. + """ + self.conflicts = False + newline = '\n' + if len(self.a) > 0: + if self.a[0].endswith('\r\n'): + newline = '\r\n' + elif self.a[0].endswith('\r'): + newline = '\r' + if base_marker and reprocess: + raise CantReprocessAndShowBase() + if name_a: + start_marker = start_marker + ' ' + name_a + if name_b: + end_marker = end_marker + ' ' + name_b + if name_base and base_marker: + base_marker = base_marker + ' ' + name_base + merge_regions = self.merge_regions() + if reprocess is True: + merge_regions = self.reprocess_merge_regions(merge_regions) + for t in merge_regions: + what = t[0] + if what == 'unchanged': + for i in range(t[1], t[2]): + yield self.base[i] + elif what == 'a' or what == 'same': + for i in range(t[1], t[2]): + yield self.a[i] + elif what == 'b': + for i in range(t[1], t[2]): + yield self.b[i] + elif what == 'conflict': + self.conflicts = True + yield start_marker + newline + for i in range(t[3], t[4]): + yield self.a[i] + if base_marker is not None: + yield base_marker + newline + for i in range(t[1], t[2]): + yield self.base[i] + yield mid_marker + newline + for i in range(t[5], t[6]): + yield self.b[i] + yield end_marker + newline + else: + raise ValueError(what) + + def merge_annotated(self): + """Return merge with conflicts, showing origin of lines. + + Most useful for debugging merge. + """ + for t in self.merge_regions(): + what = t[0] + if what == 'unchanged': + for i in range(t[1], t[2]): + yield 'u | ' + self.base[i] + elif what == 'a' or what == 'same': + for i in range(t[1], t[2]): + yield what[0] + ' | ' + self.a[i] + elif what == 'b': + for i in range(t[1], t[2]): + yield 'b | ' + self.b[i] + elif what == 'conflict': + yield '<<<<\n' + for i in range(t[3], t[4]): + yield 'A | ' + self.a[i] + yield '----\n' + for i in range(t[5], t[6]): + yield 'B | ' + self.b[i] + yield '>>>>\n' + else: + raise ValueError(what) + + def merge_groups(self): + """Yield sequence of line groups. Each one is a tuple: + + 'unchanged', lines + Lines unchanged from base + + 'a', lines + Lines taken from a + + 'same', lines + Lines taken from a (and equal to b) + + 'b', lines + Lines taken from b + + 'conflict', base_lines, a_lines, b_lines + Lines from base were changed to either a or b and conflict. + """ + for t in self.merge_regions(): + what = t[0] + if what == 'unchanged': + yield what, self.base[t[1]:t[2]] + elif what == 'a' or what == 'same': + yield what, self.a[t[1]:t[2]] + elif what == 'b': + yield what, self.b[t[1]:t[2]] + elif what == 'conflict': + yield (what, + self.base[t[1]:t[2]], + self.a[t[3]:t[4]], + self.b[t[5]:t[6]]) + else: + raise ValueError(what) + + def merge_regions(self): + """Return sequences of matching and conflicting regions. + + This returns tuples, where the first value says what kind we + have: + + 'unchanged', start, end + Take a region of base[start:end] + + 'same', astart, aend + b and a are different from base but give the same result + + 'a', start, end + Non-clashing insertion from a[start:end] + + Method is as follows: + + The two sequences align only on regions which match the base + and both descendents. These are found by doing a two-way diff + of each one against the base, and then finding the + intersections between those regions. These "sync regions" + are by definition unchanged in both and easily dealt with. + + The regions in between can be in any of three cases: + conflicted, or changed on only one side. + """ + + # section a[0:ia] has been disposed of, etc + iz = ia = ib = 0 + + for zmatch, zend, amatch, aend, bmatch, bend in self.find_sync_regions(): + #print 'match base [%d:%d]' % (zmatch, zend) + + matchlen = zend - zmatch + assert matchlen >= 0 + assert matchlen == (aend - amatch) + assert matchlen == (bend - bmatch) + + len_a = amatch - ia + len_b = bmatch - ib + len_base = zmatch - iz + assert len_a >= 0 + assert len_b >= 0 + assert len_base >= 0 + + #print 'unmatched a=%d, b=%d' % (len_a, len_b) + + if len_a or len_b: + # try to avoid actually slicing the lists + equal_a = compare_range(self.a, ia, amatch, + self.base, iz, zmatch) + equal_b = compare_range(self.b, ib, bmatch, + self.base, iz, zmatch) + same = compare_range(self.a, ia, amatch, + self.b, ib, bmatch) + + if same: + yield 'same', ia, amatch + elif equal_a and not equal_b: + yield 'b', ib, bmatch + elif equal_b and not equal_a: + yield 'a', ia, amatch + elif not equal_a and not equal_b: + yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch + else: + raise AssertionError("can't handle a=b=base but unmatched") + + ia = amatch + ib = bmatch + iz = zmatch + + # if the same part of the base was deleted on both sides + # that's OK, we can just skip it. + + + if matchlen > 0: + assert ia == amatch + assert ib == bmatch + assert iz == zmatch + + yield 'unchanged', zmatch, zend + iz = zend + ia = aend + ib = bend + + def reprocess_merge_regions(self, merge_regions): + """Where there are conflict regions, remove the agreed lines. + + Lines where both A and B have made the same changes are + eliminated. + """ + for region in merge_regions: + if region[0] != "conflict": + yield region + continue + type, iz, zmatch, ia, amatch, ib, bmatch = region + a_region = self.a[ia:amatch] + b_region = self.b[ib:bmatch] + matches = mdiff.get_matching_blocks(''.join(a_region), + ''.join(b_region)) + next_a = ia + next_b = ib + for region_ia, region_ib, region_len in matches[:-1]: + region_ia += ia + region_ib += ib + reg = self.mismatch_region(next_a, region_ia, next_b, + region_ib) + if reg is not None: + yield reg + yield 'same', region_ia, region_len+region_ia + next_a = region_ia + region_len + next_b = region_ib + region_len + reg = self.mismatch_region(next_a, amatch, next_b, bmatch) + if reg is not None: + yield reg + + def mismatch_region(next_a, region_ia, next_b, region_ib): + if next_a < region_ia or next_b < region_ib: + return 'conflict', None, None, next_a, region_ia, next_b, region_ib + mismatch_region = staticmethod(mismatch_region) + + def find_sync_regions(self): + """Return a list of sync regions, where both descendents match the base. + + Generates a list of (base1, base2, a1, a2, b1, b2). There is + always a zero-length sync region at the end of all the files. + """ + + ia = ib = 0 + amatches = mdiff.get_matching_blocks(self.basetext, self.atext) + bmatches = mdiff.get_matching_blocks(self.basetext, self.btext) + len_a = len(amatches) + len_b = len(bmatches) + + sl = [] + + while ia < len_a and ib < len_b: + abase, amatch, alen = amatches[ia] + bbase, bmatch, blen = bmatches[ib] + + # there is an unconflicted block at i; how long does it + # extend? until whichever one ends earlier. + i = intersect((abase, abase+alen), (bbase, bbase+blen)) + if i: + intbase = i[0] + intend = i[1] + intlen = intend - intbase + + # found a match of base[i[0], i[1]]; this may be less than + # the region that matches in either one + assert intlen <= alen + assert intlen <= blen + assert abase <= intbase + assert bbase <= intbase + + asub = amatch + (intbase - abase) + bsub = bmatch + (intbase - bbase) + aend = asub + intlen + bend = bsub + intlen + + assert self.base[intbase:intend] == self.a[asub:aend], \ + (self.base[intbase:intend], self.a[asub:aend]) + + assert self.base[intbase:intend] == self.b[bsub:bend] + + sl.append((intbase, intend, + asub, aend, + bsub, bend)) + + # advance whichever one ends first in the base text + if (abase + alen) < (bbase + blen): + ia += 1 + else: + ib += 1 + + intbase = len(self.base) + abase = len(self.a) + bbase = len(self.b) + sl.append((intbase, intbase, abase, abase, bbase, bbase)) + + return sl + + def find_unconflicted(self): + """Return a list of ranges in base that are not conflicted.""" + am = mdiff.get_matching_blocks(self.basetext, self.atext) + bm = mdiff.get_matching_blocks(self.basetext, self.btext) + + unc = [] + + while am and bm: + # there is an unconflicted block at i; how long does it + # extend? until whichever one ends earlier. + a1 = am[0][0] + a2 = a1 + am[0][2] + b1 = bm[0][0] + b2 = b1 + bm[0][2] + i = intersect((a1, a2), (b1, b2)) + if i: + unc.append(i) + + if a2 < b2: + del am[0] + else: + del bm[0] + + return unc + +def simplemerge(local, base, other, **opts): + def readfile(filename): + f = open(filename, "rb") + text = f.read() + f.close() + if util.binary(text): + msg = _("%s looks like a binary file.") % filename + if not opts.get('text'): + raise util.Abort(msg) + elif not opts.get('quiet'): + warn(_('warning: %s\n') % msg) + return text + + name_a = local + name_b = other + labels = opts.get('label', []) + if labels: + name_a = labels.pop(0) + if labels: + name_b = labels.pop(0) + if labels: + raise util.Abort(_("can only specify two labels.")) + + localtext = readfile(local) + basetext = readfile(base) + othertext = readfile(other) + + orig = local + local = os.path.realpath(local) + if not opts.get('print'): + opener = util.opener(os.path.dirname(local)) + out = opener(os.path.basename(local), "w", atomictemp=True) + else: + out = sys.stdout + + reprocess = not opts.get('no_minimal') + + m3 = Merge3Text(basetext, localtext, othertext) + for line in m3.merge_lines(name_a=name_a, name_b=name_b, + reprocess=reprocess): + out.write(line) + + if not opts.get('print'): + out.rename() + + if m3.conflicts: + if not opts.get('quiet'): + warn(_("warning: conflicts during merge.\n")) + return 1 diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/sshrepo.py --- a/mercurial/sshrepo.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/sshrepo.py Mon Feb 18 19:21:33 2008 +0100 @@ -114,14 +114,25 @@ return self.pipei def call(self, cmd, **args): - r = self.do_cmd(cmd, **args) - l = r.readline() + self.do_cmd(cmd, **args) + return self._recv() + + def _recv(self): + l = self.pipei.readline() self.readerr() try: l = int(l) except: self.raise_(util.UnexpectedOutput(_("unexpected response:"), l)) - return r.read(l) + return self.pipei.read(l) + + def _send(self, data, flush=False): + self.pipeo.write("%d\n" % len(data)) + if data: + self.pipeo.write(data) + if flush: + self.pipeo.flush() + self.readerr() def lock(self): self.call("lock") @@ -182,25 +193,22 @@ while 1: d = cg.read(4096) - if not d: break - self.pipeo.write(str(len(d)) + '\n') - self.pipeo.write(d) - self.readerr() + if not d: + break + self._send(d) - self.pipeo.write('0\n') - self.pipeo.flush() + self._send("", flush=True) - self.readerr() - l = int(self.pipei.readline()) - r = self.pipei.read(l) + r = self._recv() if r: # remote may send "unsynced changes" self.raise_(repo.RepoError(_("push failed: %s") % r)) - self.readerr() - l = int(self.pipei.readline()) - r = self.pipei.read(l) - return int(r) + r = self._recv() + try: + return int(r) + except: + self.raise_(util.UnexpectedOutput(_("unexpected response:"), r)) def addchangegroup(self, cg, source, url): d = self.call("addchangegroup") @@ -208,18 +216,21 @@ self.raise_(repo.RepoError(_("push refused: %s") % d)) while 1: d = cg.read(4096) - if not d: break + if not d: + break self.pipeo.write(d) self.readerr() self.pipeo.flush() self.readerr() - l = int(self.pipei.readline()) - r = self.pipei.read(l) + r = self._recv() if not r: return 1 - return int(r) + try: + return int(r) + except: + self.raise_(util.UnexpectedOutput(_("unexpected response:"), r)) def stream_out(self): return self.do_cmd('stream_out') diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/statichttprepo.py --- a/mercurial/statichttprepo.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/statichttprepo.py Mon Feb 18 19:21:33 2008 +0100 @@ -9,14 +9,16 @@ from i18n import _ import changelog, filelog, httprangereader -import repo, localrepo, manifest, os, urllib, urllib2, util +import repo, localrepo, manifest, util +import urllib, urllib2, errno class rangereader(httprangereader.httprangereader): def read(self, size=None): try: return httprangereader.httprangereader.read(self, size) except urllib2.HTTPError, inst: - raise IOError(None, inst) + num = inst.code == 404 and errno.ENOENT or None + raise IOError(num, inst) except urllib2.URLError, inst: raise IOError(None, inst.reason[1]) @@ -35,11 +37,17 @@ self.path = path.rstrip('/') + "/.hg" self.opener = opener(self.path) + # find requirements try: requirements = self.opener("requires").read().splitlines() - except IOError: - requirements = [] + except IOError, inst: + if inst.errno == errno.ENOENT: + msg = _("'%s' does not appear to be an hg repository") % path + raise repo.RepoError(msg) + else: + requirements = [] + # check them for r in requirements: if r not in self.supported: diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/templatefilters.py --- a/mercurial/templatefilters.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/templatefilters.py Mon Feb 18 19:21:33 2008 +0100 @@ -100,10 +100,6 @@ if f == -1: return util.shortuser(author) return author[:f].rstrip() -def shortdate(date): - '''turn (timestamp, tzoff) tuple into iso 8631 date.''' - return util.datestr(date, format='%Y-%m-%d', timezone=False) - def indent(text, prefix): '''indent each non-empty line of text after first with prefix.''' lines = text.splitlines() @@ -145,7 +141,7 @@ "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S"), "rfc3339date": lambda x: util.datestr(x, "%Y-%m-%dT%H:%M:%S", True, "%+03d:%02d"), "short": lambda x: x[:12], - "shortdate": shortdate, + "shortdate": util.shortdate, "stringify": templater.stringify, "strip": lambda x: x.strip(), "urlescape": lambda x: urllib.quote(x), diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/transaction.py --- a/mercurial/transaction.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/transaction.py Mon Feb 18 19:21:33 2008 +0100 @@ -15,7 +15,7 @@ import os class transaction(object): - def __init__(self, report, opener, journal, after=None): + def __init__(self, report, opener, journal, after=None, createmode=None): self.journal = None self.count = 1 @@ -27,6 +27,8 @@ self.journal = journal self.file = open(self.journal, "w") + if createmode is not None: + os.chmod(self.journal, createmode & 0666) def __del__(self): if self.journal: diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/util.py --- a/mercurial/util.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/util.py Mon Feb 18 19:21:33 2008 +0100 @@ -335,7 +335,7 @@ a.pop() b.pop() b.reverse() - return os.sep.join((['..'] * len(a)) + b) + return os.sep.join((['..'] * len(a)) + b) or '.' def canonpath(root, cwd, myname): """return the canonical path of myname, given cwd and root""" @@ -459,6 +459,8 @@ return try: pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats]) + if len(pat) > 20000: + raise OverflowError() return re.compile(pat).match except OverflowError: # We're using a Python with a tiny regex engine and we @@ -895,6 +897,13 @@ function if need.''' return path.split(os.sep) +def gui(): + '''Are we running in a GUI?''' + return os.name == "nt" or os.name == "mac" or os.environ.get("DISPLAY") + +def lookup_reg(key, name=None, scope=None): + return None + # Platform specific variants if os.name == 'nt': import msvcrt @@ -1291,7 +1300,7 @@ return openerfn(fn(path), *args, **kw) return o -def mktempcopy(name, emptyok=False): +def mktempcopy(name, emptyok=False, createmode=None): """Create a temporary file with the same contents from name The permission bits are copied from the original file. @@ -1312,7 +1321,10 @@ except OSError, inst: if inst.errno != errno.ENOENT: raise - st_mode = 0666 & ~_umask + st_mode = createmode + if st_mode is None: + st_mode = ~_umask + st_mode &= 0666 os.chmod(temp, st_mode) if emptyok: return temp @@ -1343,9 +1355,10 @@ file. When rename is called, the copy is renamed to the original name, making the changes visible. """ - def __init__(self, name, mode): + def __init__(self, name, mode, createmode): self.__name = name - self.temp = mktempcopy(name, emptyok=('w' in mode)) + self.temp = mktempcopy(name, emptyok=('w' in mode), + createmode=createmode) posixfile.__init__(self, self.temp, mode) def rename(self): @@ -1360,6 +1373,22 @@ except: pass posixfile.close(self) +def makedirs(name, mode=None): + """recursive directory creation with parent mode inheritance""" + try: + os.mkdir(name) + if mode is not None: + os.chmod(name, mode) + return + except OSError, err: + if err.errno == errno.EEXIST: + return + if err.errno != errno.ENOENT: + raise + parent = os.path.abspath(os.path.dirname(name)) + makedirs(parent, mode) + makedirs(name, mode) + class opener(object): """Open files relative to a base directory @@ -1372,6 +1401,7 @@ self.audit_path = path_auditor(base) else: self.audit_path = always + self.createmode = None def __getattr__(self, name): if name == '_can_symlink': @@ -1379,6 +1409,11 @@ return self._can_symlink raise AttributeError(name) + def _fixfilemode(self, name): + if self.createmode is None: + return + os.chmod(name, self.createmode & 0666) + def __call__(self, path, mode="r", text=False, atomictemp=False): self.audit_path(path) f = os.path.join(self.base, path) @@ -1386,6 +1421,7 @@ if not text and "b" not in mode: mode += "b" # for that other OS + nlink = -1 if mode[0] != "r": try: nlink = nlinks(f) @@ -1393,12 +1429,15 @@ nlink = 0 d = os.path.dirname(f) if not os.path.isdir(d): - os.makedirs(d) + makedirs(d, self.createmode) if atomictemp: - return atomictempfile(f, mode) + return atomictempfile(f, mode, self.createmode) if nlink > 1: rename(mktempcopy(f), f) - return posixfile(f, mode) + fp = posixfile(f, mode) + if nlink == 0: + self._fixfilemode(f) + return fp def symlink(self, src, dst): self.audit_path(dst) @@ -1410,7 +1449,7 @@ dirname = os.path.dirname(linkname) if not os.path.exists(dirname): - os.makedirs(dirname) + makedirs(dirname, self.createmode) if self._can_symlink: try: @@ -1422,6 +1461,7 @@ f = self(dst, "w") f.write(src) f.close() + self._fixfilemode(dst) class chunkbuffer(object): """Allow arbitrary sized chunks of data to be efficiently read from an @@ -1493,6 +1533,10 @@ s += timezone_format % (-tz / 3600, ((-tz % 3600) / 60)) return s +def shortdate(date=None): + """turn (timestamp, tzoff) tuple into iso 8631 date.""" + return datestr(date, format='%Y-%m-%d', timezone=False) + def strdate(string, format, defaults=[]): """parse a localized time string and return a (unixtime, offset) tuple. if the string cannot be parsed, ValueError is raised.""" @@ -1528,17 +1572,21 @@ unixtime = localunixtime + offset return unixtime, offset -def parsedate(string, formats=None, defaults=None): - """parse a localized time string and return a (unixtime, offset) tuple. +def parsedate(date, formats=None, defaults=None): + """parse a localized date/time string and return a (unixtime, offset) tuple. + The date may be a "unixtime offset" string or in one of the specified - formats.""" - if not string: + formats. If the date already is a (unixtime, offset) tuple, it is returned. + """ + if not date: return 0, 0 + if type(date) is type((0, 0)) and len(date) == 2: + return date if not formats: formats = defaultdateformats - string = string.strip() + date = date.strip() try: - when, offset = map(int, string.split(' ')) + when, offset = map(int, date.split(' ')) except ValueError: # fill out defaults if not defaults: @@ -1555,13 +1603,13 @@ for format in formats: try: - when, offset = strdate(string, format, defaults) - except ValueError: + when, offset = strdate(date, format, defaults) + except (ValueError, OverflowError): pass else: break else: - raise Abort(_('invalid date: %r ') % string) + raise Abort(_('invalid date: %r ') % date) # validate explicit (probably user-specified) date and # time zone offset. values must fit in signed 32 bits for # current 32-bit linux runtimes. timezones go from UTC-12 @@ -1656,11 +1704,9 @@ raise err for root, dirs, files in os.walk(path, onerror=errhandler): - for d in dirs: - if d == '.hg': - yield root - dirs[:] = [] - break + if '.hg' in dirs: + dirs[:] = [] # don't descend further + yield root # found a repository _rcpath = None diff -r 90e5c82a3859 -r 50a277e6ceae mercurial/util_win32.py --- a/mercurial/util_win32.py Mon Feb 18 19:20:22 2008 +0100 +++ b/mercurial/util_win32.py Mon Feb 18 19:21:33 2008 +0100 @@ -187,6 +187,37 @@ return details[0] != winerror.ERROR_INVALID_PARAMETER return True +def lookup_reg(key, valname=None, scope=None): + ''' Look up a key/value name in the Windows registry. + + valname: value name. If unspecified, the default value for the key + is used. + scope: optionally specify scope for registry lookup, this can be + a sequence of scopes to look up in order. Default (CURRENT_USER, + LOCAL_MACHINE). + ''' + try: + from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \ + QueryValueEx, OpenKey + except ImportError: + return None + + def query_val(scope, key, valname): + try: + keyhandle = OpenKey(scope, key) + return QueryValueEx(keyhandle, valname)[0] + except EnvironmentError: + return None + + if scope is None: + scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE) + elif not isinstance(scope, (list, tuple)): + scope = (scope,) + for s in scope: + val = query_val(s, key, valname) + if val is not None: + return val + def system_rcpath_win32(): '''return default os-specific hgrc search path''' proc = win32api.GetCurrentProcess() diff -r 90e5c82a3859 -r 50a277e6ceae setup.py --- a/setup.py Mon Feb 18 19:20:22 2008 +0100 +++ b/setup.py Mon Feb 18 19:21:33 2008 +0100 @@ -40,11 +40,6 @@ except ImportError: pass -if os.name in ['nt']: - extra['scripts'] = ['hg'] -else: - extra['scripts'] = ['hg', 'hgmerge'] - # specify version string, otherwise 'hg identify' will be used: version = '' @@ -77,6 +72,7 @@ url='http://selenic.com/mercurial', description='Scalable distributed SCM', license='GNU GPL', + scripts=['hg'], packages=['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert'], ext_modules=ext_modules, data_files=[(os.path.join('mercurial', root), diff -r 90e5c82a3859 -r 50a277e6ceae templates/footer.tmpl --- a/templates/footer.tmpl Mon Feb 18 19:20:22 2008 +0100 +++ b/templates/footer.tmpl Mon Feb 18 19:21:33 2008 +0100 @@ -1,7 +1,7 @@ #motd# diff -r 90e5c82a3859 -r 50a277e6ceae templates/gitweb/map --- a/templates/gitweb/map Mon Feb 18 19:20:22 2008 +0100 +++ b/templates/gitweb/map Mon Feb 18 19:21:33 2008 +0100 @@ -23,12 +23,12 @@ fileannotate = fileannotate.tmpl filediff = filediff.tmpl filelog = filelog.tmpl -fileline = '
   #linenumber# #line|escape#
' -annotateline = '#author|obfuscate#@#rev#
#line|escape#
' -difflineplus = '#line|escape#' -difflineminus = '#line|escape#' -difflineat = '#line|escape#' -diffline = '#line|escape#' +fileline = '
#linenumber# #line|escape#
' +annotateline = '#author|obfuscate#@#rev#
#linenumber#
#line|escape#
' +difflineplus = '#linenumber# #line|escape#' +difflineminus = '#linenumber# #line|escape#' +difflineat = '#linenumber# #line|escape#' +diffline = '#linenumber# #line|escape#' changelogparent = 'parent #rev#:#node|short#' changesetparent = 'parent {rev}{node|short}' filerevparent = 'parent {rev}{rename%filerename}{node|short}' diff -r 90e5c82a3859 -r 50a277e6ceae templates/header.tmpl diff -r 90e5c82a3859 -r 50a277e6ceae templates/map --- a/templates/map Mon Feb 18 19:20:22 2008 +0100 +++ b/templates/map Mon Feb 18 19:21:33 2008 +0100 @@ -22,13 +22,13 @@ fileannotate = fileannotate.tmpl filediff = filediff.tmpl filelog = filelog.tmpl -fileline = '
#linenumber##line|escape#
' +fileline = '
#linenumber##line|escape#
' filelogentry = filelogentry.tmpl -annotateline = '#author|obfuscate#@#rev#
#line|escape#
' -difflineplus = '#line|escape#' -difflineminus = '#line|escape#' -difflineat = '#line|escape#' -diffline = '#line|escape#' +annotateline = '#author|obfuscate#@#rev##linenumber#
#line|escape#
' +difflineplus = '#linenumber##line|escape#' +difflineminus = '#linenumber##line|escape#' +difflineat = '#linenumber##line|escape#' +diffline = '#linenumber##line|escape#' changelogparent = 'parent #rev#:#node|short#' changesetparent = 'parent #rev#:#node|short#' filerevparent = 'parent:{rename%filerename}{node|short}' diff -r 90e5c82a3859 -r 50a277e6ceae templates/old/header.tmpl diff -r 90e5c82a3859 -r 50a277e6ceae templates/static/hgicon.png Binary file templates/static/hgicon.png has changed diff -r 90e5c82a3859 -r 50a277e6ceae templates/static/hglogo.png Binary file templates/static/hglogo.png has changed diff -r 90e5c82a3859 -r 50a277e6ceae templates/static/style.css --- a/templates/static/style.css Mon Feb 18 19:20:22 2008 +0100 +++ b/templates/static/style.css Mon Feb 18 19:21:33 2008 +0100 @@ -34,21 +34,8 @@ pre { margin: 0; } .logo { - background-color: #333; - padding: 4pt; - margin: 8pt 0 8pt 8pt; - font-family: sans; - font-size: 60%; - color: white; float: right; clear: right; - text-align: left; -} - -.logo a { - font-weight: bold; - font-size: 150%; - color: #999; } /* Changelog/Filelog entries */ diff -r 90e5c82a3859 -r 50a277e6ceae tests/coverage.py --- a/tests/coverage.py Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/coverage.py Mon Feb 18 19:21:33 2008 +0100 @@ -218,7 +218,7 @@ firstelse = self.getFirstLine(suite) for l in range(lastprev+1, firstelse): if l in self.suite_spots: - self.doSuite(None, suite, l in exclude=self.excluded) + self.doSuite(None, suite, exclude=l in self.excluded) break else: self.doSuite(None, suite) diff -r 90e5c82a3859 -r 50a277e6ceae tests/hghave --- a/tests/hghave Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/hghave Mon Feb 18 19:21:33 2008 +0100 @@ -21,6 +21,9 @@ ret = fh.close() return (ignorestatus or ret is None) and r.search(s) +def has_baz(): + return matchoutput('baz --version 2>&1', r'baz Bazaar version') + def has_cvs(): return matchoutput('cvs --version 2>&1', r'Concurrent Versions System') @@ -85,7 +88,27 @@ def has_symlink(): return hasattr(os, "symlink") +def has_tla(): + return matchoutput('tla --version 2>&1', r'The GNU Arch Revision') + +def has_unix_permissions(): + d = tempfile.mkdtemp(prefix=tempprefix, dir=".") + try: + fname = os.path.join(d, 'foo') + for umask in (077, 007, 022): + os.umask(umask) + f = open(fname, 'w') + f.close() + mode = os.stat(fname).st_mode + os.unlink(fname) + if mode & 0777 != ~umask & 0666: + return False + return True + finally: + os.rmdir(d) + checks = { + "baz": (has_baz, "GNU Arch baz client"), "cvs": (has_cvs, "cvs client"), "cvsps": (has_cvsps, "cvsps utility"), "darcs": (has_darcs, "darcs client"), @@ -98,6 +121,8 @@ "svn": (has_svn, "subversion client and admin tools"), "svn-bindings": (has_svn_bindings, "subversion python bindings"), "symlink": (has_symlink, "symbolic links"), + "tla": (has_tla, "GNU Arch tla client"), + "unix-permissions": (has_unix_permissions, "unix-style permissions"), } def list_features(): diff -r 90e5c82a3859 -r 50a277e6ceae tests/run-tests.py --- a/tests/run-tests.py Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/run-tests.py Mon Feb 18 19:21:33 2008 +0100 @@ -420,9 +420,7 @@ HGRCPATH = None os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"' -os.environ["HGMERGE"] = ('python "%s" -L my -L other' - % os.path.join(TESTDIR, os.path.pardir, - 'contrib', 'simplemerge')) +os.environ["HGMERGE"] = "internal:merge" os.environ["HGUSER"] = "test" os.environ["HGENCODING"] = "ascii" os.environ["HGENCODINGMODE"] = "strict" diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-acl.out --- a/tests/test-acl.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-acl.out Mon Feb 18 19:21:33 2008 +0100 @@ -28,6 +28,7 @@ adding foo/file.txt revisions adding quux/file.py revisions added 3 changesets with 3 changes to 3 files +updating the branch cache rolling back last transaction 0:6675d58eff77 @@ -59,6 +60,7 @@ acl: acl.allow not enabled acl: acl.deny not enabled acl: changes have source "push" - skipping +updating the branch cache rolling back last transaction 0:6675d58eff77 @@ -94,6 +96,7 @@ acl: allowing changeset ef1ea85a6374 acl: allowing changeset f9cafe1212c8 acl: allowing changeset 911600dab2ae +updating the branch cache rolling back last transaction 0:6675d58eff77 @@ -383,6 +386,7 @@ acl: allowing changeset ef1ea85a6374 acl: allowing changeset f9cafe1212c8 acl: allowing changeset 911600dab2ae +updating the branch cache rolling back last transaction 0:6675d58eff77 @@ -578,6 +582,7 @@ acl: allowing changeset ef1ea85a6374 acl: allowing changeset f9cafe1212c8 acl: allowing changeset 911600dab2ae +updating the branch cache rolling back last transaction 0:6675d58eff77 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-add.out --- a/tests/test-add.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-add.out Mon Feb 18 19:21:33 2008 +0100 @@ -13,21 +13,26 @@ % should fail a already tracked! 1 files updated, 0 files merged, 0 files removed, 0 files unresolved +merging a warning: conflicts during merge. -merging a merging a failed! 0 files updated, 0 files merged, 0 files removed, 1 files unresolved There are unresolved merges, you can redo the full merge using: hg update -C 2 hg merge 1 M a +? a.orig % should fail a already tracked! M a +? a.orig % issue683 R a +? a.orig M a +? a.orig c does not exist! d does not exist! M a A c +? a.orig diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-archive --- a/tests/test-archive Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-archive Mon Feb 18 19:21:33 2008 +0100 @@ -69,6 +69,8 @@ echo 'rev-0.tar created' fi +hg archive -t bogus test.bogus + echo % server errors cat errors.log diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-archive.out --- a/tests/test-archive.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-archive.out Mon Feb 18 19:21:33 2008 +0100 @@ -39,6 +39,7 @@ test-TIP/baz/bletch test-TIP/foo rev-0.tar created +abort: unknown archive type 'bogus' % server errors % empty repo abort: repository has no revisions diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-bheads --- a/tests/test-bheads Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-bheads Mon Feb 18 19:21:33 2008 +0100 @@ -1,108 +1,113 @@ #!/bin/sh +heads() +{ + hg heads --template '#rev#: #desc|firstline|strip#\n' "$@" +} + hg init a cd a echo 'root' >root hg add root -hg commit -d '0 0' -u test -m "Adding root node" -hg heads +hg commit -m "Adding root node" +heads echo '-------' -hg heads . +heads . echo '=======' echo 'a' >a hg add a hg branch a -hg commit -d '1 0' -u test -m "Adding a branch" -hg heads +hg commit -m "Adding a branch" +heads echo '-------' -hg heads . +heads . echo '=======' hg update -C 0 echo 'b' >b hg add b hg branch b -hg commit -d '2 0' -u test -m "Adding b branch" -hg heads +hg commit -m "Adding b branch" +heads echo '-------' -hg heads . +heads . echo '=======' echo 'bh1' >bh1 hg add bh1 -hg commit -d '3 0' -u test -m "Adding b branch head 1" -hg heads +hg commit -m "Adding b branch head 1" +heads echo '-------' -hg heads . +heads . echo '=======' hg update -C 2 echo 'bh2' >bh2 hg add bh2 -hg commit -d '4 0' -u test -m "Adding b branch head 2" -hg heads +hg commit -m "Adding b branch head 2" +heads echo '-------' -hg heads . +heads . echo '=======' hg update -C 2 echo 'bh3' >bh3 hg add bh3 -hg commit -d '5 0' -u test -m "Adding b branch head 3" -hg heads +hg commit -m "Adding b branch head 3" +heads echo '-------' -hg heads . +heads . echo '=======' hg merge 4 -hg commit -d '6 0' -u test -m "Merging b branch head 2 and b branch head 3" -hg heads +hg commit -m "Merging b branch head 2 and b branch head 3" +heads echo '-------' -hg heads . +heads . echo '=======' echo 'c' >c hg add c hg branch c -hg commit -d '7 0' -u test -m "Adding c branch" -hg heads +hg commit -m "Adding c branch" +heads echo '-------' -hg heads . +heads . echo '=======' -hg heads -r 3 . +heads -r 3 . echo $? echo '-------' -hg heads -r 2 . +heads -r 2 . echo $? echo '-------' hg update -C 4 echo $? echo '-------' -hg heads -r 3 . +heads -r 3 . echo $? echo '-------' -hg heads -r 2 . +heads -r 2 . echo $? echo '-------' -hg heads -r 7 . +heads -r 7 . echo $? echo '=======' for i in 0 1 2 3 4 5 6 7; do hg update -C "$i" - hg heads + heads echo '-------' - hg heads . + heads . echo '-------' done echo '=======' for i in a b c z; do - hg heads "$i" + heads "$i" echo '-------' done echo '=======' -hg heads 0 1 2 3 4 5 6 7 +heads 0 1 2 3 4 5 6 7 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-bheads.out --- a/tests/test-bheads.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-bheads.out Mon Feb 18 19:21:33 2008 +0100 @@ -1,608 +1,151 @@ -changeset: 0:19709c5a4e75 -tag: tip -user: test -date: Thu Jan 01 00:00:00 1970 +0000 -summary: Adding root node - +0: Adding root node ------- -changeset: 0:19709c5a4e75 -tag: tip -user: test -date: Thu Jan 01 00:00:00 1970 +0000 -summary: Adding root node - +0: Adding root node ======= marked working directory as branch a -changeset: 1:dd6b440dd85a -branch: a -tag: tip -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +1: Adding a branch ------- -changeset: 1:dd6b440dd85a -branch: a -tag: tip -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +1: Adding a branch ======= 0 files updated, 0 files merged, 1 files removed, 0 files unresolved marked working directory as branch b -changeset: 2:ac22033332d1 -branch: b -tag: tip -parent: 0:19709c5a4e75 -user: test -date: Thu Jan 01 00:00:02 1970 +0000 -summary: Adding b branch - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +2: Adding b branch +1: Adding a branch ------- -changeset: 2:ac22033332d1 -branch: b -tag: tip -parent: 0:19709c5a4e75 -user: test -date: Thu Jan 01 00:00:02 1970 +0000 -summary: Adding b branch - +2: Adding b branch ======= -changeset: 3:aee39cd168d0 -branch: b -tag: tip -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 3:aee39cd168d0 -branch: b -tag: tip -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - +3: Adding b branch head 1 ======= 0 files updated, 0 files merged, 1 files removed, 0 files unresolved -changeset: 4:22df7444f7c1 -branch: b -tag: tip -parent: 2:ac22033332d1 -user: test -date: Thu Jan 01 00:00:04 1970 +0000 -summary: Adding b branch head 2 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +4: Adding b branch head 2 +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 4:22df7444f7c1 -branch: b -tag: tip -parent: 2:ac22033332d1 -user: test -date: Thu Jan 01 00:00:04 1970 +0000 -summary: Adding b branch head 2 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - +4: Adding b branch head 2 +3: Adding b branch head 1 ======= 0 files updated, 0 files merged, 1 files removed, 0 files unresolved -changeset: 5:0d57af4f9583 -branch: b -tag: tip -parent: 2:ac22033332d1 -user: test -date: Thu Jan 01 00:00:05 1970 +0000 -summary: Adding b branch head 3 - -changeset: 4:22df7444f7c1 -branch: b -parent: 2:ac22033332d1 -user: test -date: Thu Jan 01 00:00:04 1970 +0000 -summary: Adding b branch head 2 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +5: Adding b branch head 3 +4: Adding b branch head 2 +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 5:0d57af4f9583 -branch: b -tag: tip -parent: 2:ac22033332d1 -user: test -date: Thu Jan 01 00:00:05 1970 +0000 -summary: Adding b branch head 3 - -changeset: 4:22df7444f7c1 -branch: b -parent: 2:ac22033332d1 -user: test -date: Thu Jan 01 00:00:04 1970 +0000 -summary: Adding b branch head 2 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - +5: Adding b branch head 3 +4: Adding b branch head 2 +3: Adding b branch head 1 ======= 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) -changeset: 6:00432327d822 -branch: b -tag: tip -parent: 5:0d57af4f9583 -parent: 4:22df7444f7c1 -user: test -date: Thu Jan 01 00:00:06 1970 +0000 -summary: Merging b branch head 2 and b branch head 3 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +6: Merging b branch head 2 and b branch head 3 +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 6:00432327d822 -branch: b -tag: tip -parent: 5:0d57af4f9583 -parent: 4:22df7444f7c1 -user: test -date: Thu Jan 01 00:00:06 1970 +0000 -summary: Merging b branch head 2 and b branch head 3 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - +6: Merging b branch head 2 and b branch head 3 +3: Adding b branch head 1 ======= marked working directory as branch c -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +7: Adding c branch +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - +7: Adding c branch ======= no changes on branch c containing . are reachable from 3 1 ------- -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - +7: Adding c branch 0 ------- 0 files updated, 0 files merged, 2 files removed, 0 files unresolved 0 ------- -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - +3: Adding b branch head 1 0 ------- -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 6:00432327d822 -branch: b -parent: 5:0d57af4f9583 -parent: 4:22df7444f7c1 -user: test -date: Thu Jan 01 00:00:06 1970 +0000 -summary: Merging b branch head 2 and b branch head 3 - +3: Adding b branch head 1 +6: Merging b branch head 2 and b branch head 3 0 ------- no changes on branch b containing . are reachable from 7 1 ======= 0 files updated, 0 files merged, 2 files removed, 0 files unresolved -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +7: Adding c branch +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 0:19709c5a4e75 -user: test -date: Thu Jan 01 00:00:00 1970 +0000 -summary: Adding root node - +0: Adding root node ------- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +7: Adding c branch +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +1: Adding a branch ------- 1 files updated, 0 files merged, 1 files removed, 0 files unresolved -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +7: Adding c branch +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 6:00432327d822 -branch: b -parent: 5:0d57af4f9583 -parent: 4:22df7444f7c1 -user: test -date: Thu Jan 01 00:00:06 1970 +0000 -summary: Merging b branch head 2 and b branch head 3 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - +6: Merging b branch head 2 and b branch head 3 +3: Adding b branch head 1 ------- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +7: Adding c branch +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 6:00432327d822 -branch: b -parent: 5:0d57af4f9583 -parent: 4:22df7444f7c1 -user: test -date: Thu Jan 01 00:00:06 1970 +0000 -summary: Merging b branch head 2 and b branch head 3 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - +6: Merging b branch head 2 and b branch head 3 +3: Adding b branch head 1 ------- 1 files updated, 0 files merged, 1 files removed, 0 files unresolved -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +7: Adding c branch +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 6:00432327d822 -branch: b -parent: 5:0d57af4f9583 -parent: 4:22df7444f7c1 -user: test -date: Thu Jan 01 00:00:06 1970 +0000 -summary: Merging b branch head 2 and b branch head 3 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - +6: Merging b branch head 2 and b branch head 3 +3: Adding b branch head 1 ------- 1 files updated, 0 files merged, 1 files removed, 0 files unresolved -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +7: Adding c branch +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 6:00432327d822 -branch: b -parent: 5:0d57af4f9583 -parent: 4:22df7444f7c1 -user: test -date: Thu Jan 01 00:00:06 1970 +0000 -summary: Merging b branch head 2 and b branch head 3 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - +6: Merging b branch head 2 and b branch head 3 +3: Adding b branch head 1 ------- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +7: Adding c branch +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 6:00432327d822 -branch: b -parent: 5:0d57af4f9583 -parent: 4:22df7444f7c1 -user: test -date: Thu Jan 01 00:00:06 1970 +0000 -summary: Merging b branch head 2 and b branch head 3 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - +6: Merging b branch head 2 and b branch head 3 +3: Adding b branch head 1 ------- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +7: Adding c branch +3: Adding b branch head 1 +1: Adding a branch ------- -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - +7: Adding c branch ------- ======= -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - +1: Adding a branch ------- -changeset: 6:00432327d822 -branch: b -parent: 5:0d57af4f9583 -parent: 4:22df7444f7c1 -user: test -date: Thu Jan 01 00:00:06 1970 +0000 -summary: Merging b branch head 2 and b branch head 3 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - +6: Merging b branch head 2 and b branch head 3 +3: Adding b branch head 1 ------- -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - +7: Adding c branch ------- abort: unknown revision 'z'! ------- ======= -changeset: 0:19709c5a4e75 -user: test -date: Thu Jan 01 00:00:00 1970 +0000 -summary: Adding root node - -changeset: 1:dd6b440dd85a -branch: a -user: test -date: Thu Jan 01 00:00:01 1970 +0000 -summary: Adding a branch - -changeset: 6:00432327d822 -branch: b -parent: 5:0d57af4f9583 -parent: 4:22df7444f7c1 -user: test -date: Thu Jan 01 00:00:06 1970 +0000 -summary: Merging b branch head 2 and b branch head 3 - -changeset: 3:aee39cd168d0 -branch: b -user: test -date: Thu Jan 01 00:00:03 1970 +0000 -summary: Adding b branch head 1 - -changeset: 7:9fb091bb9835 -branch: c -tag: tip -user: test -date: Thu Jan 01 00:00:07 1970 +0000 -summary: Adding c branch - +0: Adding root node +1: Adding a branch +6: Merging b branch head 2 and b branch head 3 +3: Adding b branch head 1 +7: Adding c branch diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-branches --- a/tests/test-branches Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-branches Mon Feb 18 19:21:33 2008 +0100 @@ -34,3 +34,9 @@ hg branches echo '-------' hg branches -a + +echo "--- Branch a" +hg log -b a + +echo "---- Branch b" +hg log -b b diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-branches.out --- a/tests/test-branches.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-branches.out Mon Feb 18 19:21:33 2008 +0100 @@ -10,3 +10,31 @@ ------- c 5:5ca481e59b8c a 1:dd6b440dd85a +--- Branch a +changeset: 1:dd6b440dd85a +branch: a +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: Adding a branch + +---- Branch b +changeset: 4:22df7444f7c1 +branch: b +parent: 2:ac22033332d1 +user: test +date: Thu Jan 01 00:00:04 1970 +0000 +summary: Adding b branch head 2 + +changeset: 3:aee39cd168d0 +branch: b +user: test +date: Thu Jan 01 00:00:03 1970 +0000 +summary: Adding b branch head 1 + +changeset: 2:ac22033332d1 +branch: b +parent: 0:19709c5a4e75 +user: test +date: Thu Jan 01 00:00:02 1970 +0000 +summary: Adding b branch + diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-bundle --- a/tests/test-bundle Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-bundle Mon Feb 18 19:21:33 2008 +0100 @@ -70,7 +70,14 @@ #doesn't work (yet ?) #hg -R bundle://../full.hg verify hg pull bundle://../full.hg +echo "====== Rollback empty" +hg rollback cd .. +echo "====== Log -R bundle:empty+full.hg" +hg -R bundle:empty+full.hg log --template="{rev} " +echo "" +echo "====== Pull full.hg into empty again (using -R; with hook)" +hg -R empty pull full.hg echo "====== Create partial clones" rm -r empty diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-bundle.out --- a/tests/test-bundle.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-bundle.out Mon Feb 18 19:21:33 2008 +0100 @@ -124,6 +124,19 @@ adding file changes added 9 changesets with 7 changes to 4 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) +====== Rollback empty +rolling back last transaction +====== Log -R bundle:empty+full.hg +8 7 6 5 4 3 2 1 0 +====== Pull full.hg into empty again (using -R; with hook) +changegroup hook: HG_NODE=5649c9d34dd87d0ecb5fd39672128376e83b22e1 HG_SOURCE=pull HG_URL=bundle:empty+full.hg +pulling from full.hg +requesting all changes +adding changesets +adding manifests +adding file changes +added 9 changesets with 7 changes to 4 files (+1 heads) +(run 'hg heads' to see heads, 'hg merge' to merge) ====== Create partial clones requesting all changes adding changesets diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-cat --- a/tests/test-cat Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-cat Mon Feb 18 19:21:33 2008 +0100 @@ -8,6 +8,7 @@ hg ci -A -m m -d "1000000 0" hg rm a hg cat a +hg cat --decode a # more tests in test-encode sleep 1 # make sure mtime is changed echo 1 > b hg ci -m m -d "1000000 0" diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-cat.out --- a/tests/test-cat.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-cat.out Mon Feb 18 19:21:33 2008 +0100 @@ -3,5 +3,6 @@ 0 0 0 +0 a: No such file in rev 03f6b0774996 1 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-clone --- a/tests/test-clone Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-clone Mon Feb 18 19:21:33 2008 +0100 @@ -32,4 +32,8 @@ hg clone file://a e grep 'file:' e/.hg/hgrc +# check that path aliases are expanded +hg clone -q -U --config 'paths.foobar=a#0' foobar f +hg -R f showconfig paths.default | sed -e 's,.*/,,' + exit 0 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-clone.out --- a/tests/test-clone.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-clone.out Mon Feb 18 19:21:33 2008 +0100 @@ -15,3 +15,4 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved a 1 files updated, 0 files merged, 0 files removed, 0 files unresolved +a#0 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-commit --- a/tests/test-commit Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-commit Mon Feb 18 19:21:33 2008 +0100 @@ -1,10 +1,5 @@ #!/bin/sh -cleanpath() -{ - sed -e "s:/.*\(/test/.*\):...\1:" -} - echo % commit date test hg init test cd test @@ -19,11 +14,12 @@ hg commit -d ' 1 4444' -m commit-6 hg commit -d '111111111111 0' -m commit-7 -echo % partial commit test +echo % commit added file that has been deleted echo bar > bar hg add bar rm bar -hg commit -d "1000000 0" -m commit-8 2>&1 | cleanpath +hg commit -d "1000000 0" -m commit-8 +hg commit -d "1000000 0" -m commit-8-2 bar hg -q revert -a --no-backup @@ -34,22 +30,22 @@ echo > dir.file hg add -hg commit -d '0 0' -m commit-10 dir dir.file 2>&1 | cleanpath +hg commit -d '0 0' -m commit-10 dir dir.file echo >> dir/file mkdir bleh mkdir dir2 cd bleh -hg commit -d '0 0' -m commit-11 . 2>&1 | cleanpath -hg commit -d '0 0' -m commit-12 ../dir ../dir2 2>&1 | cleanpath +hg commit -d '0 0' -m commit-11 . +hg commit -d '0 0' -m commit-12 ../dir ../dir2 hg -v commit -d '0 0' -m commit-13 ../dir cd .. -hg commit -d '0 0' -m commit-14 does-not-exist 2>&1 | cleanpath +hg commit -d '0 0' -m commit-14 does-not-exist ln -s foo baz -hg commit -d '0 0' -m commit-15 baz 2>&1 | cleanpath +hg commit -d '0 0' -m commit-15 baz touch quux -hg commit -d '0 0' -m commit-16 quux 2>&1 | cleanpath +hg commit -d '0 0' -m commit-16 quux echo >> dir/file hg -v commit -d '0 0' -m commit-17 dir/file cd .. diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-commit.out --- a/tests/test-commit.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-commit.out Mon Feb 18 19:21:33 2008 +0100 @@ -2,30 +2,24 @@ transaction abort! rollback completed abort: empty commit message -transaction abort! -rollback completed abort: impossible time zone offset: 4444444 -transaction abort! -rollback completed abort: invalid date: '1\t15.1' -transaction abort! -rollback completed abort: invalid date: 'foo bar' +abort: date exceeds 32 bits: 111111111111 +% commit added file that has been deleted nothing changed -% partial commit test -trouble committing bar! -abort: No such file or directory: .../test/bar +abort: file bar not found! adding dir/file dir/file adding dir.file -abort: no match under directory .../test/dir! -abort: no match under directory .../test/bleh! -abort: no match under directory .../test/dir2! +abort: no match under directory dir! +abort: no match under directory .! +abort: no match under directory ../dir2! dir/file does-not-exist: No such file or directory -abort: file .../test/does-not-exist not found! -abort: file .../test/baz not tracked! -abort: file .../test/quux not tracked! +abort: file does-not-exist not found! +abort: file baz not tracked! +abort: file quux not tracked! dir/file % partial subdir commit test adding bar/bar diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-conflict.out --- a/tests/test-conflict.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-conflict.out Mon Feb 18 19:21:33 2008 +0100 @@ -1,15 +1,16 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved +merging a warning: conflicts during merge. -merging a merging a failed! 0 files updated, 0 files merged, 0 files removed, 1 files unresolved There are unresolved merges, you can redo the full merge using: hg update -C 2 hg merge 1 e7fe8eb3e180+0d24b7662d3e+ tip -<<<<<<< my +<<<<<<< local something else ======= something >>>>>>> other M a +? a.orig diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-convert-baz --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-convert-baz Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,72 @@ +#!/bin/sh + +"$TESTDIR/hghave" baz || exit 80 + +mkdir do_not_use_HOME_baz +cd do_not_use_HOME_baz +HOME=`pwd`; export HOME +cd .. +baz my-id "mercurial " + +echo "[extensions]" >> $HGRCPATH +echo "convert=" >> $HGRCPATH +echo 'hgext.graphlog =' >> $HGRCPATH + +echo % create baz archive +baz make-archive baz@mercurial--convert hg-test-convert-baz + +echo % initialize baz repo +mkdir baz-repo +cd baz-repo/ +baz init-tree baz@mercurial--convert/baz--test--0 +baz import + +echo % create initial files +echo 'this is a file' > a +baz add a +mkdir src +baz add src +cd src +dd count=1 if=/dev/zero of=b > /dev/null 2> /dev/null +baz add b +baz commit -s "added a file, src and src/b (binary)" + +echo % create link file and modify a +ln -s ../a a-link +baz add a-link +echo 'this a modification to a' >> ../a +baz commit -s "added link to a and modify a" + +echo % create second link and modify b +ln -s ../a a-link-2 +baz add a-link-2 +dd count=1 seek=1 if=/dev/zero of=b > /dev/null 2> /dev/null +baz commit -s "added second link and modify b" + +echo % b file to link and a-link-2 to regular file +rm -f a-link-2 +echo 'this is now a regular file' > a-link-2 +ln -sf ../a b +baz commit -s "file to link and link to file test" + +echo % move a-link-2 file and src directory +cd .. +baz mv src/a-link-2 c +baz mv src test +baz commit -s "move and rename a-link-2 file and src directory" + +cd .. + +echo % converting baz repo to Mercurial +hg convert baz-repo baz-repo-hg + +baz register-archive -d baz@mercurial--convert + +glog() +{ + hg glog --template '#rev# "#desc|firstline#" files: #files#\n' "$@" +} + +echo % show graph log +glog -R baz-repo-hg +hg -R baz-repo-hg manifest --debug diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-convert-baz.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-convert-baz.out Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,75 @@ +% create baz archive +% initialize baz repo +* creating version baz@mercurial--convert/baz--test--0 +* imported baz@mercurial--convert/baz--test--0 +% create initial files +* build pristine tree for baz@mercurial--convert/baz--test--0--base-0 +* Scanning for full-tree revision: . +* from import revision: baz@mercurial--convert/baz--test--0--base-0 +A/ .arch-ids +A/ src +A/ src/.arch-ids +A .arch-ids/a.id +A a +A src/.arch-ids/=id +A src/.arch-ids/b.id +A src/b +* update pristine tree (baz@mercurial--convert/baz--test--0--base-0 => baz--test--0--patch-1) +* committed baz@mercurial--convert/baz--test--0--patch-1 +% create link file and modify a +A src/.arch-ids/a-link.id +A src/a-link +M a +* update pristine tree (baz@mercurial--convert/baz--test--0--patch-1 => baz--test--0--patch-2) +* committed baz@mercurial--convert/baz--test--0--patch-2 +% create second link and modify b +A src/.arch-ids/a-link-2.id +A src/a-link-2 +Mb src/b +* update pristine tree (baz@mercurial--convert/baz--test--0--patch-2 => baz--test--0--patch-3) +* committed baz@mercurial--convert/baz--test--0--patch-3 +% b file to link and a-link-2 to regular file +fl src/b +lf src/a-link-2 +* update pristine tree (baz@mercurial--convert/baz--test--0--patch-3 => baz--test--0--patch-4) +* committed baz@mercurial--convert/baz--test--0--patch-4 +% move a-link-2 file and src directory +D/ src/.arch-ids +A/ test/.arch-ids +/> src test +=> src/.arch-ids/a-link-2.id .arch-ids/c.id +=> src/a-link-2 c +=> src/.arch-ids/=id test/.arch-ids/=id +=> src/.arch-ids/a-link.id test/.arch-ids/a-link.id +=> src/.arch-ids/b.id test/.arch-ids/b.id +* update pristine tree (baz@mercurial--convert/baz--test--0--patch-4 => baz--test--0--patch-5) +* committed baz@mercurial--convert/baz--test--0--patch-5 +% converting baz repo to Mercurial +initializing destination baz-repo-hg repository +analyzing tree version baz@mercurial--convert/baz--test--0... +scanning source... +sorting... +converting... +5 initial import +4 added a file, src and src/b (binary) +3 added link to a and modify a +2 added second link and modify b +1 file to link and link to file test +0 move and rename a-link-2 file and src directory +% show graph log +o 5 "move and rename a-link-2 file and src directory" files: c src/a-link src/a-link-2 src/b test/a-link test/b +| +o 4 "file to link and link to file test" files: src/a-link-2 src/b +| +o 3 "added second link and modify b" files: src/a-link-2 src/b +| +o 2 "added link to a and modify a" files: a src/a-link +| +o 1 "added a file, src and src/b (binary)" files: a src/b +| +o 0 "initial import" files: + +c4072c4b72e1cabace081888efa148ee80ca3cbb 644 a +e3207be798aaf87a444a62903621edab4ddc1fb6 644 c +1f6b5bb93f1da278ef1fead1e4740a03d8802e9f 644 @ test/a-link +1f6b5bb93f1da278ef1fead1e4740a03d8802e9f 644 @ test/b diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-convert-clonebranches.out --- a/tests/test-convert-clonebranches.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-convert-clonebranches.out Mon Feb 18 19:21:33 2008 +0100 @@ -16,11 +16,11 @@ (branch merge, don't forget to commit) marked working directory as branch branch3 % incremental conversion -2 c1 -pulling from branch0 into branch1 +2 c2 +pulling from branch0 into branch2 2 changesets found -1 c2 -pulling from branch0 into branch2 +1 c1 +pulling from branch0 into branch1 2 changesets found 0 c3 pulling from branch2 into branch3 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-convert-datesort --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-convert-datesort Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,40 @@ +#!/bin/sh + +cat >> $HGRCPATH <> a +hg ci -Am a0 -d '1 0' +hg branch brancha +echo a >> a +hg ci -m a1 -d '2 0' +echo a >> a +hg ci -m a2 -d '3 0' +echo a >> a +hg ci -m a3 -d '4 0' +hg up -C 0 +hg branch branchb +echo b >> b +hg ci -Am b0 -d '5 0' +hg up -C brancha +echo a >> a +hg ci -m a4 -d '6 0' +echo a >> a +hg ci -m a5 -d '7 0' +echo a >> a +hg ci -m a6 -d '8 0' +hg up -C branchb +echo b >> b +hg ci -m b1 -d '9 0' +cd .. + +echo % convert with datesort +hg convert --datesort t t2 +echo % graph converted repo +hg -R t2 glog --template '#rev# "#desc#"\n' + diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-convert-datesort.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-convert-datesort.out Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,40 @@ +adding a +marked working directory as branch brancha +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +marked working directory as branch branchb +adding b +1 files updated, 0 files merged, 1 files removed, 0 files unresolved +2 files updated, 0 files merged, 0 files removed, 0 files unresolved +% convert with datesort +initializing destination t2 repository +scanning source... +sorting... +converting... +8 a0 +7 a1 +6 a2 +5 a3 +4 b0 +3 a4 +2 a5 +1 a6 +0 b1 +% graph converted repo +o 8 "b1" +| +| o 7 "a6" +| | +| o 6 "a5" +| | +| o 5 "a4" +| | +o | 4 "b0" +| | +| o 3 "a3" +| | +| o 2 "a2" +| | +| o 1 "a1" +|/ +o 0 "a0" + diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-convert-svn-sink.out --- a/tests/test-convert-svn-sink.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-convert-svn-sink.out Mon Feb 18 19:21:33 2008 +0100 @@ -260,8 +260,8 @@ adding right-1 adding right-2 3 files updated, 0 files merged, 2 files removed, 0 files unresolved +merging b warning: conflicts during merge. -merging b merging b failed! 2 files updated, 0 files merged, 0 files removed, 1 files unresolved There are unresolved merges, you can redo the full merge using: diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-convert-tla --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-convert-tla Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,72 @@ +#!/bin/sh + +"$TESTDIR/hghave" tla || exit 80 + +mkdir do_not_use_HOME_tla +cd do_not_use_HOME_tla +HOME=`pwd`; export HOME +cd .. +tla my-id "mercurial " + +echo "[extensions]" >> $HGRCPATH +echo "convert=" >> $HGRCPATH +echo 'hgext.graphlog =' >> $HGRCPATH + +echo % create tla archive +tla make-archive tla@mercurial--convert `pwd`/hg-test-convert-tla + +echo % initialize tla repo +mkdir tla-repo +cd tla-repo/ +tla init-tree tla@mercurial--convert/tla--test--0 +tla import + +echo % create initial files +echo 'this is a file' > a +tla add a +mkdir src +tla add src +cd src +dd count=1 if=/dev/zero of=b > /dev/null 2> /dev/null +tla add b +tla commit -s "added a file, src and src/b (binary)" + +echo % create link file and modify a +ln -s ../a a-link +tla add a-link +echo 'this a modification to a' >> ../a +tla commit -s "added link to a and modify a" + +echo % create second link and modify b +ln -s ../a a-link-2 +tla add a-link-2 +dd count=1 seek=1 if=/dev/zero of=b > /dev/null 2> /dev/null +tla commit -s "added second link and modify b" + +echo % b file to link and a-link-2 to regular file +rm -f a-link-2 +echo 'this is now a regular file' > a-link-2 +ln -sf ../a b +tla commit -s "file to link and link to file test" + +echo % move a-link-2 file and src directory +cd .. +tla mv src/a-link-2 c +tla mv src test +tla commit -s "move and rename a-link-2 file and src directory" + +cd .. + +echo % converting tla repo to Mercurial +hg convert tla-repo tla-repo-hg + +tla register-archive -d tla@mercurial--convert + +glog() +{ + hg glog --template '#rev# "#desc|firstline#" files: #files#\n' "$@" +} + +echo % show graph log +glog -R tla-repo-hg +hg -R tla-repo-hg manifest --debug diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-convert-tla.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-convert-tla.out Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,72 @@ +% create tla archive +% initialize tla repo +* creating version tla@mercurial--convert/tla--test--0 +* imported tla@mercurial--convert/tla--test--0 +% create initial files +A/ .arch-ids +A/ src +A/ src/.arch-ids +A .arch-ids/a.id +A a +A src/.arch-ids/=id +A src/.arch-ids/b.id +A src/b +* update pristine tree (tla@mercurial--convert/tla--test--0--base-0 => tla--test--0--patch-1) +* committed tla@mercurial--convert/tla--test--0--patch-1 +% create link file and modify a +A src/.arch-ids/a-link.id +A src/a-link +M a +* update pristine tree (tla@mercurial--convert/tla--test--0--patch-1 => tla--test--0--patch-2) +* committed tla@mercurial--convert/tla--test--0--patch-2 +% create second link and modify b +A src/.arch-ids/a-link-2.id +A src/a-link-2 +Mb src/b +* update pristine tree (tla@mercurial--convert/tla--test--0--patch-2 => tla--test--0--patch-3) +* committed tla@mercurial--convert/tla--test--0--patch-3 +% b file to link and a-link-2 to regular file +fl src/b +lf src/a-link-2 +* update pristine tree (tla@mercurial--convert/tla--test--0--patch-3 => tla--test--0--patch-4) +* committed tla@mercurial--convert/tla--test--0--patch-4 +% move a-link-2 file and src directory +D/ src/.arch-ids +A/ test/.arch-ids +/> src test +=> src/.arch-ids/a-link-2.id .arch-ids/c.id +=> src/a-link-2 c +=> src/.arch-ids/=id test/.arch-ids/=id +=> src/.arch-ids/a-link.id test/.arch-ids/a-link.id +=> src/.arch-ids/b.id test/.arch-ids/b.id +* update pristine tree (tla@mercurial--convert/tla--test--0--patch-4 => tla--test--0--patch-5) +* committed tla@mercurial--convert/tla--test--0--patch-5 +% converting tla repo to Mercurial +initializing destination tla-repo-hg repository +analyzing tree version tla@mercurial--convert/tla--test--0... +scanning source... +sorting... +converting... +5 initial import +4 added a file, src and src/b (binary) +3 added link to a and modify a +2 added second link and modify b +1 file to link and link to file test +0 move and rename a-link-2 file and src directory +% show graph log +o 5 "move and rename a-link-2 file and src directory" files: c src/a-link src/a-link-2 src/b test/a-link test/b +| +o 4 "file to link and link to file test" files: src/a-link-2 src/b +| +o 3 "added second link and modify b" files: src/a-link-2 src/b +| +o 2 "added link to a and modify a" files: a src/a-link +| +o 1 "added a file, src and src/b (binary)" files: a src/b +| +o 0 "initial import" files: + +c4072c4b72e1cabace081888efa148ee80ca3cbb 644 a +e3207be798aaf87a444a62903621edab4ddc1fb6 644 c +1f6b5bb93f1da278ef1fead1e4740a03d8802e9f 644 @ test/a-link +1f6b5bb93f1da278ef1fead1e4740a03d8802e9f 644 @ test/b diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-convert.out --- a/tests/test-convert.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-convert.out Mon Feb 18 19:21:33 2008 +0100 @@ -8,6 +8,7 @@ - Darcs - git - Subversion + - GNU Arch Accepted destination formats: - Mercurial diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-copy-move-merge.out --- a/tests/test-copy-move-merge.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-copy-move-merge.out Mon Feb 18 19:21:33 2008 +0100 @@ -14,11 +14,15 @@ a: remote moved to b -> m copying a to b copying a to c +picked tool 'internal:merge' for a (binary False symlink False) merging a and b my a@fb3948d97f07+ other b@40da226db0f0 ancestor a@583c7b748052 + premerge successful removing a +picked tool 'internal:merge' for a (binary False symlink False) merging a and c my a@fb3948d97f07+ other c@40da226db0f0 ancestor a@583c7b748052 + premerge successful 0 files updated, 2 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) -- b -- diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-custom-filters --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-custom-filters Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,60 @@ +#!/bin/sh + +hg init + +cat > .hg/hgrc < prefix.py < .hgignore < stuff.txt <> stuff.txt < morestuff.txt < m foo: remote copied to bar -> m copying foo to bar +picked tool 'internal:merge' for foo (binary False symlink False) merging foo and bar my foo@2092631ce82b+ other bar@7731dad1c2b9 ancestor foo@310fd17130da + premerge successful +picked tool 'internal:merge' for foo (binary False symlink False) merging foo my foo@2092631ce82b+ other foo@7731dad1c2b9 ancestor foo@310fd17130da + premerge successful 0 files updated, 2 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) -- foo -- diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-encode --- a/tests/test-encode Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-encode Mon Feb 18 19:21:33 2008 +0100 @@ -32,3 +32,11 @@ echo %% uncompress our new working dir copy gunzip < a.gz + +echo %% check hg cat operation +hg cat a.gz +hg cat --decode a.gz | gunzip +mkdir subdir +cd subdir +hg -R .. cat ../a.gz +hg -R .. cat --decode ../a.gz | gunzip diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-encode.out --- a/tests/test-encode.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-encode.out Mon Feb 18 19:21:33 2008 +0100 @@ -7,3 +7,8 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved %% uncompress our new working dir copy this is a test +%% check hg cat operation +this is a test +this is a test +this is a test +this is a test diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-grep.out --- a/tests/test-grep.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-grep.out Mon Feb 18 19:21:33 2008 +0100 @@ -1,5 +1,5 @@ % pattern error -grep: invalid match pattern: nothing to repeat! +grep: invalid match pattern: nothing to repeat % simple port:4:export port:4:vaportight diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-help.out --- a/tests/test-help.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-help.out Mon Feb 18 19:21:33 2008 +0100 @@ -205,6 +205,7 @@ -w --ignore-all-space ignore white space when comparing lines -b --ignore-space-change ignore changes in the amount of white space -B --ignore-blank-lines ignore changes whose lines are all blank + -U --unified number of lines of context to show (default: 3) -I --include include names matching the given patterns -X --exclude exclude names matching the given patterns @@ -216,8 +217,10 @@ show changed files in the working directory Show status of files in the repository. If names are given, only - files that match are shown. Files that are clean or ignored, are - not listed unless -c (clean), -i (ignored) or -A is given. + files that match are shown. Files that are clean or ignored or + source of a copy/move operation, are not listed unless -c (clean), + -i (ignored), -C (copies) or -A is given. Unless options described + with "show only ..." are given, the options -mardu are used. NOTE: status may appear to disagree with diff if permissions have changed or a merge has occurred. The standard diff format does not @@ -234,7 +237,7 @@ C = clean ! = deleted, but still tracked ? = not tracked - I = ignored (not shown by default) + I = ignored = the previous added file was copied from here options: diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-hgweb-commands.out Binary file tests/test-hgweb-commands.out has changed diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-hgweb.out --- a/tests/test-hgweb.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-hgweb.out Mon Feb 18 19:21:33 2008 +0100 @@ -43,8 +43,8 @@ diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-import --- a/tests/test-import Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-import Mon Feb 18 19:21:33 2008 +0100 @@ -125,6 +125,18 @@ hg --cwd b tip --template '{desc}\n' rm -r b +# We weren't backing up the correct dirstate file when importing many patches +# (issue963) +echo '% import patch1 patch2; rollback' +echo line 3 >> a/a +hg --cwd a ci -m'third change' +hg --cwd a export -o '../patch%R' 1 2 +hg clone -qr0 a b +hg --cwd b parents --template 'parent: #rev#\n' +hg --cwd b import ../patch1 ../patch2 +hg --cwd b rollback +hg --cwd b parents --template 'parent: #rev#\n' +rm -r b # bug non regression test # importing a patch in a subdirectory failed at the commit stage diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-import.out --- a/tests/test-import.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-import.out Mon Feb 18 19:21:33 2008 +0100 @@ -152,6 +152,12 @@ next line --- +% import patch1 patch2; rollback +parent: 0 +applying ../patch1 +applying ../patch2 +rolling back last transaction +parent: 1 % hg import in a subdirectory requesting all changes adding changesets diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-inherit-mode --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-inherit-mode Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,90 @@ +#!/bin/sh + +# test that new files created in .hg inherit the permissions from .hg/store + +"$TESTDIR/hghave" unix-permissions || exit 80 + +mkdir dir +# just in case somebody has a strange $TMPDIR +chmod g-s dir +cd dir + +cat >printmodes.py <mode.py < /dev/null +mkdir dir +touch dir/file +hg ci -qAm 'add dir/file' +storemode=`python ../mode.py .hg/store` +dirmode=`python ../mode.py .hg/store/data/dir` +if [ "$storemode" != "$dirmode" ]; then + echo "$storemode != $dirmode" +fi + diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-inherit-mode.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-inherit-mode.out Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,54 @@ +% before commit +% store can be written by the group, other files cannot +% store is setgid +00700 ./.hg/ +00600 ./.hg/00changelog.i +00600 ./.hg/requires +00770 ./.hg/store/ + +% after commit +% working dir files can only be written by the owner +% files created in .hg can be written by the group +% (in particular, store/**, dirstate, branch.cache, undo files) +% new directories are setgid +00700 ./.hg/ +00600 ./.hg/00changelog.i +00660 ./.hg/dirstate +00600 ./.hg/requires +00770 ./.hg/store/ +00660 ./.hg/store/00changelog.i +00660 ./.hg/store/00manifest.i +00770 ./.hg/store/data/ +00770 ./.hg/store/data/dir/ +00660 ./.hg/store/data/dir/bar.i +00660 ./.hg/store/data/foo.i +00660 ./.hg/store/undo +00660 ./.hg/undo.branch +00660 ./.hg/undo.dirstate +00700 ./dir/ +00600 ./dir/bar +00600 ./foo + +% before push +% group can write everything +00770 ../push/.hg/ +00660 ../push/.hg/00changelog.i +00660 ../push/.hg/requires +00770 ../push/.hg/store/ + +% after push +% group can still write everything +00770 ../push/.hg/ +00660 ../push/.hg/00changelog.i +00660 ../push/.hg/branch.cache +00660 ../push/.hg/requires +00770 ../push/.hg/store/ +00660 ../push/.hg/store/00changelog.i +00660 ../push/.hg/store/00manifest.i +00770 ../push/.hg/store/data/ +00770 ../push/.hg/store/data/dir/ +00660 ../push/.hg/store/data/dir/bar.i +00660 ../push/.hg/store/data/foo.i +00660 ../push/.hg/store/undo +00660 ../push/.hg/undo.branch +00660 ../push/.hg/undo.dirstate diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-install.out --- a/tests/test-install.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-install.out Mon Feb 18 19:21:33 2008 +0100 @@ -2,7 +2,6 @@ Checking extensions... Checking templates... Checking patch... -Checking merge helper... Checking commit editor... Checking username... No problems detected diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-issue352.out --- a/tests/test-issue352.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-issue352.out Mon Feb 18 19:21:33 2008 +0100 @@ -1,13 +1,13 @@ adding he llo -abort: '\n' and '\r' disallowed in filenames +abort: '\n' and '\r' disallowed in filenames: 'he\rllo' adding he llo -abort: '\n' and '\r' disallowed in filenames +abort: '\n' and '\r' disallowed in filenames: 'he\rllo' adding hell o -abort: '\n' and '\r' disallowed in filenames +abort: '\n' and '\r' disallowed in filenames: 'hell\no' adding hell o -abort: '\n' and '\r' disallowed in filenames +abort: '\n' and '\r' disallowed in filenames: 'hell\no' f he llo he llo f hell o hell diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-issue672.out --- a/tests/test-issue672.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-issue672.out Mon Feb 18 19:21:33 2008 +0100 @@ -28,8 +28,10 @@ 1a -> 1 * checking for directory renames 1a: local moved to 1 -> m +picked tool 'internal:merge' for 1a (binary False symlink False) merging 1a and 1 my 1a@ac7575e3c052+ other 1@746e9549ea96 ancestor 1@81f4b099af3d + premerge successful 0 files updated, 1 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) 1 files updated, 0 files merged, 1 files removed, 0 files unresolved @@ -44,8 +46,10 @@ checking for directory renames 1: remote moved to 1a -> m copying 1 to 1a +picked tool 'internal:merge' for 1 (binary False symlink False) merging 1 and 1a my 1@746e9549ea96+ other 1a@ac7575e3c052 ancestor 1@81f4b099af3d + premerge successful removing 1 0 files updated, 1 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-keyword --- a/tests/test-keyword Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-keyword Mon Feb 18 19:21:33 2008 +0100 @@ -4,6 +4,7 @@ [extensions] hgext.keyword = hgext.mq = +hgext.notify = [keyword] * = b = ignore @@ -24,19 +25,31 @@ hg --quiet kwdemo "Branch = {branches}" -hg init Test -cd Test +hg init Test-bndl +cd Test-bndl echo % kwshrink should exit silently in empty/invalid repo hg kwshrink +# Symlinks cannot be created on Windows. The bundle was made with: +# +# hg init t +# cd t +# echo a > a +# ln -s a sym +# hg add sym +# hg ci -m addsym -u mercurial +# hg bundle --base null ../test-keyword.hg +# +hg pull -u "$TESTDIR/test-keyword.hg" \ + | sed 's/pulling from.*test-keyword.hg/pulling from test-keyword.hg/' + echo 'expand $Id$' > a echo 'do not process $Id:' >> a echo 'xxx $' >> a echo 'ignore $Id$' > b -ln -s a sym echo % cat -cat sym a b +cat a b echo % addremove hg addremove @@ -56,7 +69,7 @@ echo % identify hg --quiet identify echo % cat -cat sym a b +cat a b echo % hg cat hg cat sym a b @@ -69,6 +82,33 @@ mv $HGRCPATH.nohook $HGRCPATH rm hooktest +echo % bundle +hg bundle --base null ../kw.hg + +cd .. +hg init Test +cd Test + +echo % notify on pull to check whether keywords stay as is in email +echo % ie. if patch.diff wrapper acts as it should + +cat <> $HGRCPATH +[hooks] +incoming.notify = python:hgext.notify.hook +[notify] +sources = pull +diffstat = False +[reposubs] +* = Test +EOF + +echo % pull from bundle +hg pull -u ../kw.hg 2>&1 | sed -e '/^Date:/,/^diffs (/ d' + +echo % remove notify config +sed -e '/\[hooks\]/,$ d' $HGRCPATH > $HGRCPATH.nonotify +mv $HGRCPATH.nonotify $HGRCPATH + echo % touch touch a b echo % status @@ -78,7 +118,7 @@ echo % update hg update echo % cat -cat sym a b +cat a b echo % check whether expansion is filewise echo '$Id$' > c @@ -90,8 +130,12 @@ echo % compare changenodes in a c cat a c +echo % qinit -c +hg qinit -c echo % qimport hg qimport -r tip -n mqtest.diff +echo % qcommit +hg qcommit -mqtest echo % keywords should not be expanded in patch cat .hg/patches/mqtest.diff echo % qpop @@ -123,7 +167,7 @@ hg kwfiles echo % diff --rev -hg diff --rev 0 | grep -v 'b/c' +hg diff --rev 1 | grep -v 'b/c' echo % rollback hg rollback @@ -143,7 +187,7 @@ EOF echo % cat -cat sym a b +cat a b echo % hg cat hg cat sym a b @@ -166,7 +210,7 @@ hg status echo % cat -cat sym a b +cat a b echo % hg cat hg cat sym a b echo @@ -187,7 +231,7 @@ echo % clone to test incoming cd .. -hg clone -r0 Test Test-a +hg clone -r1 Test Test-a cd Test-a cat <> .hg/hgrc [paths] @@ -208,7 +252,7 @@ echo % import hg import ../rejecttest.diff echo % cat -cat sym a b +cat a b echo echo % rollback hg rollback @@ -234,20 +278,20 @@ cd .. echo % kwexpand nonexistent -hg kwexpand nonexistent +hg kwexpand nonexistent 2>&1 | sed 's/nonexistent:.*/nonexistent:/' echo % switch off expansion echo % kwshrink with unknown file u cp a u hg --verbose kwshrink echo % cat -cat sym a b +cat a b echo % hg cat hg cat sym a b echo rm $HGRCPATH echo % cat -cat sym a b +cat a b echo % hg cat hg cat sym a b echo diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-keyword.hg Binary file tests/test-keyword.hg has changed diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-keyword.out --- a/tests/test-keyword.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-keyword.out Mon Feb 18 19:21:33 2008 +0100 @@ -84,69 +84,95 @@ Branch = {branches} $Branch: demobranch $ % kwshrink should exit silently in empty/invalid repo +pulling from test-keyword.hg +requesting all changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +1 files updated, 0 files merged, 0 files removed, 0 files unresolved % cat expand $Id$ do not process $Id: xxx $ -expand $Id$ -do not process $Id: -xxx $ ignore $Id$ % addremove adding a adding b -adding sym % status A a A b -A sym % default keyword expansion including commit hook % interrupted commit should not change state or run commit hook a b -sym transaction abort! rollback completed abort: empty commit message % status A a A b -A sym % commit a b -sym overwriting a expanding keywords running hook commit.test: cp a hooktest % status ? hooktest % identify -f782df5f9602 +ef63ca68695b % cat -expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $ -do not process $Id: -xxx $ -expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $ +expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $ do not process $Id: xxx $ ignore $Id$ % hg cat -expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $ +expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $ do not process $Id: xxx $ ignore $Id$ a % diff a hooktest % removing commit hook from config +% bundle +2 changesets found +% notify on pull to check whether keywords stay as is in email +% ie. if patch.diff wrapper acts as it should +% pull from bundle +pulling from ../kw.hg +requesting all changes +adding changesets +adding manifests +adding file changes +added 2 changesets with 3 changes to 3 files + +diff -r 000000000000 -r a2392c293916 sym +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/sym Sat Feb 09 20:25:47 2008 +0100 +@@ -0,0 +1,1 @@ ++a +\ No newline at end of file + +diff -r a2392c293916 -r ef63ca68695b a +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/a Thu Jan 01 00:00:00 1970 +0000 +@@ -0,0 +1,3 @@ ++expand $Id$ ++do not process $Id: ++xxx $ +diff -r a2392c293916 -r ef63ca68695b b +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/b Thu Jan 01 00:00:00 1970 +0000 +@@ -0,0 +1,1 @@ ++ignore $Id$ +3 files updated, 0 files merged, 0 files removed, 0 files unresolved +% remove notify config % touch % status % update 3 files updated, 0 files merged, 0 files removed, 0 files unresolved % cat -expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $ -do not process $Id: -xxx $ -expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $ +expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $ do not process $Id: xxx $ ignore $Id$ @@ -157,21 +183,23 @@ overwriting a expanding keywords overwriting c expanding keywords % compare changenodes in a c -expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $ +expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $ do not process $Id: xxx $ -$Id: c,v ba4426d1938e 1970/01/01 00:00:01 user $ +$Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $ tests for different changenodes +% qinit -c % qimport +% qcommit % keywords should not be expanded in patch # HG changeset patch # User User Name # Date 1 0 -# Node ID ba4426d1938ec9673e03ab274d88c44e24618f7f -# Parent f782df5f9602483b4e51c31a12315f353bba380c +# Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad +# Parent ef63ca68695bc9495032c6fda1350c71e6d256e9 cndiff -diff -r f782df5f9602 -r ba4426d1938e c +diff -r ef63ca68695b -r 40a904bbbe4c c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/c Thu Jan 01 00:00:01 1970 +0000 @@ -0,0 +1,2 @@ @@ -183,7 +211,7 @@ applying mqtest.diff Now at: mqtest.diff % cat -$Id: c,v ba4426d1938e 1970/01/01 00:00:01 user $ +$Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $ tests for different changenodes % qpop and move on Patch queue now empty @@ -196,10 +224,10 @@ c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292 overwriting c expanding keywords % cat a c -expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $ +expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $ do not process $Id: xxx $ -expand $Id: c,v 0ba462c0f077 1970/01/01 00:00:01 user $ +expand $Id: c,v e22d299ac0c2 1970/01/01 00:00:01 user $ do not process $Id: xxx $ % touch copied c after 1 second @@ -208,7 +236,7 @@ a c % diff --rev -diff -r f782df5f9602 c +diff -r ef63ca68695b c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -0,0 +1,3 @@ +expand $Id$ @@ -232,15 +260,12 @@ Xinfo = {author}: {desc} $Xinfo: test: hg keyword config and expansion example $ % cat -expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $ -do not process $Id: -xxx $ -expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $ +expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $ do not process $Id: xxx $ ignore $Id$ % hg cat -expand $Id: a f782df5f9602 Thu, 01 Jan 1970 00:00:00 +0000 user $ +expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $ do not process $Id: xxx $ ignore $Id$ @@ -257,17 +282,13 @@ overwriting a expanding keywords % status % cat -expand $Id: a 0729690beff6 Thu, 01 Jan 1970 00:00:02 +0000 user $ -do not process $Id: -xxx $ -$Xinfo: User Name : firstline $ -expand $Id: a 0729690beff6 Thu, 01 Jan 1970 00:00:02 +0000 user $ +expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $ do not process $Id: xxx $ $Xinfo: User Name : firstline $ ignore $Id$ % hg cat -expand $Id: a 0729690beff6 Thu, 01 Jan 1970 00:00:02 +0000 user $ +expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $ do not process $Id: xxx $ $Xinfo: User Name : firstline $ @@ -281,7 +302,7 @@ R a % revert a % cat a -expand $Id: a 0729690beff6 Thu, 01 Jan 1970 00:00:02 +0000 user $ +expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $ do not process $Id: xxx $ $Xinfo: User Name : firstline $ @@ -290,12 +311,12 @@ adding changesets adding manifests adding file changes -added 1 changesets with 3 changes to 3 files +added 2 changesets with 3 changes to 3 files 3 files updated, 0 files merged, 0 files removed, 0 files unresolved % incoming comparing with test-keyword/Test searching for changes -changeset: 1:0729690beff6 +changeset: 2:bb948857c743 tag: tip user: User Name date: Thu Jan 01 00:00:02 1970 +0000 @@ -308,11 +329,7 @@ % import applying ../rejecttest.diff % cat -expand $Id: a 82983f13f138 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest -do not process $Id: rejecttest -xxx $ -$Xinfo: User Name : rejects? $ -expand $Id: a 82983f13f138 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest +expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest do not process $Id: rejecttest xxx $ $Xinfo: User Name : rejects? $ @@ -332,7 +349,7 @@ x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e overwriting x/a expanding keywords % cat a -expand $Id: x/a f27c134d2d9b Thu, 01 Jan 1970 00:00:03 +0000 user $ +expand $Id: x/a cfa68229c116 Thu, 01 Jan 1970 00:00:03 +0000 user $ do not process $Id: xxx $ $Xinfo: User Name : xa $ @@ -344,7 +361,7 @@ xxx $ $Xinfo$ % kwexpand nonexistent -nonexistent: No such file or directory +nonexistent: % switch off expansion % kwshrink with unknown file u overwriting a shrinking keywords @@ -354,13 +371,9 @@ do not process $Id: xxx $ $Xinfo$ -expand $Id$ -do not process $Id: -xxx $ -$Xinfo$ ignore $Id$ % hg cat -expand $Id: a 0729690beff6 Thu, 01 Jan 1970 00:00:02 +0000 user $ +expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $ do not process $Id: xxx $ $Xinfo: User Name : firstline $ @@ -371,10 +384,6 @@ do not process $Id: xxx $ $Xinfo$ -expand $Id$ -do not process $Id: -xxx $ -$Xinfo$ ignore $Id$ % hg cat expand $Id$ diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-merge-commit.out --- a/tests/test-merge-commit.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-merge-commit.out Mon Feb 18 19:21:33 2008 +0100 @@ -25,8 +25,10 @@ ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 7d3b554bfdf1 searching for copies back to rev 1 bar: versions differ -> m +picked tool 'internal:merge' for bar (binary False symlink False) merging bar my bar@2d2f9a22c82b+ other bar@7d3b554bfdf1 ancestor bar@0a3ab4856510 + premerge successful 0 files updated, 1 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) % contents of bar should be line1 line2 @@ -71,8 +73,10 @@ ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 96ab80c60897 searching for copies back to rev 1 bar: versions differ -> m +picked tool 'internal:merge' for bar (binary False symlink False) merging bar my bar@2d2f9a22c82b+ other bar@96ab80c60897 ancestor bar@0a3ab4856510 + premerge successful 0 files updated, 1 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) % contents of bar should be line1 line2 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-merge-local.out --- a/tests/test-merge-local.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-merge-local.out Mon Feb 18 19:21:33 2008 +0100 @@ -18,27 +18,28 @@ M zzz2_merge_bad # local merge with bad merge tool merging zzz1_merge_ok -merging zzz1_merge_ok failed! merging zzz2_merge_bad merging zzz2_merge_bad failed! -3 files updated, 0 files merged, 2 files removed, 2 files unresolved +3 files updated, 1 files merged, 2 files removed, 1 files unresolved There are unresolved merges with locally modified files. -You can redo the full merge using: +You can finish the partial merge using: hg update 0 hg update 1 2 files updated, 0 files merged, 3 files removed, 0 files unresolved --- a/zzz1_merge_ok +++ b/zzz1_merge_ok ++new first line +new last line --- a/zzz2_merge_bad +++ b/zzz2_merge_bad +another last line M zzz1_merge_ok M zzz2_merge_bad +? zzz2_merge_bad.orig # local merge with conflicts -warning: conflicts during merge. merging zzz1_merge_ok merging zzz2_merge_bad +warning: conflicts during merge. merging zzz2_merge_bad failed! 3 files updated, 1 files merged, 2 files removed, 1 files unresolved There are unresolved merges with locally modified files. @@ -57,6 +58,7 @@ +new last line M zzz1_merge_ok M zzz2_merge_bad +? zzz2_merge_bad.orig # local merge without conflicts merging zzz1_merge_ok 4 files updated, 1 files merged, 2 files removed, 0 files unresolved diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-merge-revert2.out --- a/tests/test-merge-revert2.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-merge-revert2.out Mon Feb 18 19:21:33 2008 +0100 @@ -9,8 +9,8 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved f248da0d4c3e tip 1 files updated, 0 files merged, 0 files removed, 0 files unresolved +merging file1 warning: conflicts during merge. -merging file1 merging file1 failed! 0 files updated, 0 files merged, 0 files removed, 1 files unresolved There are unresolved merges with locally modified files. @@ -23,15 +23,19 @@ @@ -1,3 +1,7 @@ added file1 another line of text -+<<<<<<< my ++<<<<<<< local +changed file1 different +======= changed file1 +>>>>>>> other M file1 +? file1.orig f248da0d4c3e+ tip reverting file1 +? file1.orig f248da0d4c3e tip +? file1.orig f248da0d4c3e tip 0 files updated, 0 files merged, 0 files removed, 0 files unresolved +? file1.orig f248da0d4c3e tip diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-merge7.out --- a/tests/test-merge7.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-merge7.out Mon Feb 18 19:21:33 2008 +0100 @@ -6,8 +6,8 @@ adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) +merging test.txt warning: conflicts during merge. -merging test.txt merging test.txt failed! 0 files updated, 0 files merged, 0 files removed, 1 files unresolved There are unresolved merges, you can redo the full merge using: @@ -20,21 +20,22 @@ adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) -warning: conflicts during merge. resolving manifests overwrite None partial False ancestor faaea63e63a9 local 451c744aabcc+ remote a070d41e8360 searching for copies back to rev 1 test.txt: versions differ -> m +picked tool 'internal:merge' for test.txt (binary False symlink False) merging test.txt my test.txt@451c744aabcc+ other test.txt@a070d41e8360 ancestor test.txt@faaea63e63a9 +warning: conflicts during merge. merging test.txt failed! 0 files updated, 0 files merged, 0 files removed, 1 files unresolved There are unresolved merges, you can redo the full merge using: hg update -C 3 hg merge 4 one -<<<<<<< my +<<<<<<< local two-point-five ======= two-point-one diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-merge9.out --- a/tests/test-merge9.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-merge9.out Mon Feb 18 19:21:33 2008 +0100 @@ -5,8 +5,7 @@ merging bar merging bar failed! merging foo and baz -merging baz failed! -1 files updated, 0 files merged, 0 files removed, 2 files unresolved +1 files updated, 1 files merged, 0 files removed, 1 files unresolved There are unresolved merges, you can redo the full merge using: hg update -C 2 hg merge 1 @@ -14,8 +13,7 @@ merging bar merging bar failed! merging baz and foo -merging baz failed! -1 files updated, 0 files merged, 0 files removed, 2 files unresolved +1 files updated, 1 files merged, 0 files removed, 1 files unresolved There are unresolved merges, you can redo the full merge using: hg update -C 1 hg merge 2 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-mq --- a/tests/test-mq Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-mq Mon Feb 18 19:21:33 2008 +0100 @@ -42,6 +42,12 @@ hg --cwd c qinit -c hg -R c/.hg/patches st +echo % qnew should refuse bad patch names +hg -R c qnew series +hg -R c qnew status +hg -R c qnew guards +hg -R c qnew .hgignore + echo % qnew implies add hg -R c qnew test.patch @@ -297,6 +303,13 @@ echo % mq tags hg log --template '{rev} {tags}\n' -r qparent:qtip +echo % bad node in status +hg qpop +hg strip -qn tip +hg tip 2>&1 | sed -e 's/unknown node .*/unknown node/' +hg branches 2>&1 | sed -e 's/unknown node .*/unknown node/' +hg qpop + cat >>$HGRCPATH < writelines.py <> $HGRCPATH +echo "mq=" >> $HGRCPATH +echo "[diff]" >> $HGRCPATH +echo "git=1" >> $HGRCPATH + +echo % build diff with CRLF +hg init repo +cd repo +python ../writelines.py b 5 'a\n' 5 'a\r\n' +hg ci -Am addb +python ../writelines.py b 2 'a\n' 10 'b\n' 2 'a\r\n' +hg diff > b.diff +hg up -C +echo % qimport CRLF diff +hg qimport b.diff +hg qpush + + diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-mq-qimport.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-mq-qimport.out Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,7 @@ +% build diff with CRLF +adding b +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +% qimport CRLF diff +adding b.diff to series file +applying b.diff +Now at: b.diff diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-mq-safety --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-mq-safety Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,44 @@ +#!/bin/sh + +echo '[extensions]' >> $HGRCPATH +echo 'hgext.mq =' >> $HGRCPATH + +hg init repo +cd repo + +echo foo > foo +hg ci -qAm 'add a file' + +hg qinit + +hg qnew foo +echo foo >> foo +hg qrefresh -m 'append foo' + +hg qnew bar +echo bar >> foo +hg qrefresh -m 'append bar' + +echo '% try to commit on top of a patch' +echo quux >> foo +hg ci -m 'append quux' + +# cheat a bit... +mv .hg/patches .hg/patches2 +hg ci -m 'append quux' +mv .hg/patches2 .hg/patches + +echo '% qpop/qrefresh on the wrong revision' +hg qpop +hg qpop -n patches 2>&1 | sed -e 's/\(using patch queue:\).*/\1/' +hg qrefresh + +hg up -C qtip +echo '% qpop' +hg qpop + +echo '% qrefresh' +hg qrefresh + +echo '% tip:' +hg tip --template '#rev# #desc#\n' diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-mq-safety.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-mq-safety.out Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,14 @@ +% try to commit on top of a patch +abort: cannot commit over an applied mq patch +% qpop/qrefresh on the wrong revision +abort: working directory revision is not qtip +using patch queue: +abort: popping would remove a revision not managed by this patch queue +abort: working directory revision is not qtip +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +% qpop +abort: popping would remove a revision not managed by this patch queue +% qrefresh +abort: cannot refresh a revision with children +% tip: +3 append quux diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-mq.out --- a/tests/test-mq.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-mq.out Mon Feb 18 19:21:33 2008 +0100 @@ -59,12 +59,19 @@ % qinit -c A .hgignore A series +% qnew should refuse bad patch names +abort: "series" cannot be used as the name of a patch +abort: "status" cannot be used as the name of a patch +abort: "guards" cannot be used as the name of a patch +abort: ".hgignore" cannot be used as the name of a patch % qnew implies add A .hgignore A series A test.patch % qinit; qinit -c .hgignore: +^\.hg +^\.mq syntax: glob status guards @@ -281,6 +288,18 @@ 0 qparent 1 qbase foo 2 qtip bar tip +% bad node in status +Now at: foo +changeset: 0:cb9a9f314b8b +mq status file refers to unknown node +tag: tip +user: test +date: Thu Jan 01 00:00:00 1970 +0000 +summary: a + +mq status file refers to unknown node +default 0:cb9a9f314b8b +abort: working directory revision is not qtip new file diff --git a/new b/new diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-newbranch --- a/tests/test-newbranch Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-newbranch Mon Feb 18 19:21:33 2008 +0100 @@ -41,6 +41,15 @@ hg log -qr foo cat .hg/branch.cache +echo % push should update the branch cache +hg init ../target +echo % pushing just rev 0 +hg push -qr 0 ../target +cat ../target/.hg/branch.cache +echo % pushing everything +hg push -qf ../target +cat ../target/.hg/branch.cache + echo % update with no arguments: tipmost revision of the current branch hg up -q -C 0 hg up -q diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-newbranch.out --- a/tests/test-newbranch.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-newbranch.out Mon Feb 18 19:21:33 2008 +0100 @@ -63,7 +63,7 @@ date: Mon Jan 12 13:46:40 1970 +0000 summary: modify a branch -Invalid branch cache: unknown tip +invalidating branch cache (tip differs) changeset: 4:4909a3732169c0c20011c4f4b8fdff4e3d89b23f branch: foo tag: tip @@ -83,6 +83,15 @@ bf1bc2f45e834c75404d0ddab57d53beab56e2f8 default 4909a3732169c0c20011c4f4b8fdff4e3d89b23f foo 67ec16bde7f1575d523313b9bca000f6a6f12dca bar +% push should update the branch cache +% pushing just rev 0 +be8523e69bf892e25817fc97187516b3c0804ae4 0 +be8523e69bf892e25817fc97187516b3c0804ae4 default +% pushing everything +4909a3732169c0c20011c4f4b8fdff4e3d89b23f 4 +bf1bc2f45e834c75404d0ddab57d53beab56e2f8 default +4909a3732169c0c20011c4f4b8fdff4e3d89b23f foo +67ec16bde7f1575d523313b9bca000f6a6f12dca bar % update with no arguments: tipmost revision of the current branch bf1bc2f45e83 4909a3732169 (foo) tip diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-parse-date.out --- a/tests/test-parse-date.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-parse-date.out Mon Feb 18 19:21:33 2008 +0100 @@ -3,14 +3,8 @@ merging with changeset 2:e6c3abc120e7 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) -transaction abort! -rollback completed abort: invalid date: 'should fail' -transaction abort! -rollback completed abort: date exceeds 32 bits: 100000000000000000 -transaction abort! -rollback completed abort: impossible time zone offset: 1400000 Sun Jan 15 13:30:00 2006 +0500 Sun Jan 15 13:30:00 2006 -0800 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-push-warn.out --- a/tests/test-push-warn.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-push-warn.out Mon Feb 18 19:21:33 2008 +0100 @@ -33,7 +33,7 @@ searching for changes abort: push creates new remote branches! (did you forget to merge? use push -f to force) -0 +1 pushing to ../c searching for changes no changes found @@ -42,12 +42,12 @@ searching for changes abort: push creates new remote branches! (did you forget to merge? use push -f to force) -0 +1 pushing to ../c searching for changes abort: push creates new remote branches! (did you forget to merge? use push -f to force) -0 +1 pushing to ../c searching for changes adding changesets diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-rename-merge1.out --- a/tests/test-rename-merge1.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-rename-merge1.out Mon Feb 18 19:21:33 2008 +0100 @@ -19,8 +19,10 @@ a: remote moved to b -> m b2: remote created -> g copying a to b +picked tool 'internal:merge' for a (binary False symlink False) merging a and b my a@f26ec4fc3fa3+ other b@8e765a822af2 ancestor a@af1939970a1c + premerge successful removing a warning: detected divergent renames of a2 to: c2 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-rename-merge2.out --- a/tests/test-rename-merge2.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-rename-merge2.out Mon Feb 18 19:21:33 2008 +0100 @@ -13,8 +13,11 @@ rev: versions differ -> m a: remote copied to b -> m copying a to b +picked tool 'python ../merge' for a (binary False symlink False) merging a and b my a@e300d1c794ec+ other b@735846fee2d7 ancestor a@924404dff337 + premerge successful +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@e300d1c794ec+ other rev@735846fee2d7 ancestor rev@924404dff337 0 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -41,8 +44,11 @@ b: local copied to a -> m rev: versions differ -> m getting a +picked tool 'python ../merge' for b (binary False symlink False) merging b and a my b@ac809aeed39a+ other a@f4db7e329e71 ancestor a@924404dff337 + premerge successful +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ac809aeed39a+ other rev@f4db7e329e71 ancestor rev@924404dff337 1 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -68,9 +74,12 @@ rev: versions differ -> m a: remote moved to b -> m copying a to b +picked tool 'python ../merge' for a (binary False symlink False) merging a and b my a@e300d1c794ec+ other b@e03727d2d66b ancestor a@924404dff337 + premerge successful removing a +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@e300d1c794ec+ other rev@e03727d2d66b ancestor rev@924404dff337 0 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -94,8 +103,11 @@ checking for directory renames b: local moved to a -> m rev: versions differ -> m +picked tool 'python ../merge' for b (binary False symlink False) merging b and a my b@ecf3cb2a4219+ other a@f4db7e329e71 ancestor a@924404dff337 + premerge successful +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ecf3cb2a4219+ other rev@f4db7e329e71 ancestor rev@924404dff337 0 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -120,6 +132,7 @@ rev: versions differ -> m b: remote created -> g getting b +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@94b33a1b7f2d+ other rev@735846fee2d7 ancestor rev@924404dff337 1 files updated, 1 files merged, 0 files removed, 0 files unresolved @@ -142,6 +155,7 @@ b -> a checking for directory renames rev: versions differ -> m +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ac809aeed39a+ other rev@97c705ade336 ancestor rev@924404dff337 0 files updated, 1 files merged, 0 files removed, 0 files unresolved @@ -168,6 +182,7 @@ b: remote created -> g removing a getting b +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@94b33a1b7f2d+ other rev@e03727d2d66b ancestor rev@924404dff337 1 files updated, 1 files merged, 1 files removed, 0 files unresolved @@ -189,6 +204,7 @@ b -> a checking for directory renames rev: versions differ -> m +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ecf3cb2a4219+ other rev@97c705ade336 ancestor rev@924404dff337 0 files updated, 1 files merged, 0 files removed, 0 files unresolved @@ -206,8 +222,10 @@ searching for copies back to rev 1 b: versions differ -> m rev: versions differ -> m +picked tool 'python ../merge' for b (binary False symlink False) merging b my b@ec03c2ca8642+ other b@79cc6877a3b7 ancestor a@924404dff337 +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ec03c2ca8642+ other rev@79cc6877a3b7 ancestor rev@924404dff337 0 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -238,6 +256,7 @@ b c getting c +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ecf3cb2a4219+ other rev@e6abcc1a30c2 ancestor rev@924404dff337 1 files updated, 1 files merged, 0 files removed, 0 files unresolved @@ -256,8 +275,10 @@ searching for copies back to rev 1 b: versions differ -> m rev: versions differ -> m +picked tool 'python ../merge' for b (binary False symlink False) merging b my b@ac809aeed39a+ other b@af30c7647fc7 ancestor b@000000000000 +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ac809aeed39a+ other rev@af30c7647fc7 ancestor rev@924404dff337 0 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -278,8 +299,10 @@ b: versions differ -> m rev: versions differ -> m removing a +picked tool 'python ../merge' for b (binary False symlink False) merging b my b@59318016310c+ other b@e03727d2d66b ancestor b@000000000000 +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@59318016310c+ other rev@e03727d2d66b ancestor rev@924404dff337 0 files updated, 2 files merged, 1 files removed, 0 files unresolved @@ -299,8 +322,10 @@ b: versions differ -> m rev: versions differ -> m getting a +picked tool 'python ../merge' for b (binary False symlink False) merging b my b@ac809aeed39a+ other b@8dbce441892a ancestor b@000000000000 +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ac809aeed39a+ other rev@8dbce441892a ancestor rev@924404dff337 1 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -321,8 +346,10 @@ b: versions differ -> m rev: versions differ -> m removing a +picked tool 'python ../merge' for b (binary False symlink False) merging b my b@59318016310c+ other b@e03727d2d66b ancestor b@000000000000 +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@59318016310c+ other rev@e03727d2d66b ancestor rev@924404dff337 0 files updated, 2 files merged, 1 files removed, 0 files unresolved @@ -342,8 +369,10 @@ b: versions differ -> m rev: versions differ -> m getting a +picked tool 'python ../merge' for b (binary False symlink False) merging b my b@ac809aeed39a+ other b@8dbce441892a ancestor b@000000000000 +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ac809aeed39a+ other rev@8dbce441892a ancestor rev@924404dff337 1 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -362,8 +391,10 @@ searching for copies back to rev 1 b: versions differ -> m rev: versions differ -> m +picked tool 'python ../merge' for b (binary False symlink False) merging b my b@0b76e65c8289+ other b@735846fee2d7 ancestor b@000000000000 +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@0b76e65c8289+ other rev@735846fee2d7 ancestor rev@924404dff337 0 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -384,8 +415,10 @@ rev: versions differ -> m a: prompt recreating -> g getting a +picked tool 'python ../merge' for b (binary False symlink False) merging b my b@ecf3cb2a4219+ other b@8dbce441892a ancestor b@000000000000 +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ecf3cb2a4219+ other rev@8dbce441892a ancestor rev@924404dff337 1 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -404,8 +437,10 @@ searching for copies back to rev 1 b: versions differ -> m rev: versions differ -> m +picked tool 'python ../merge' for b (binary False symlink False) merging b my b@0b76e65c8289+ other b@e03727d2d66b ancestor b@000000000000 +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@0b76e65c8289+ other rev@e03727d2d66b ancestor rev@924404dff337 0 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -430,9 +465,11 @@ rev: versions differ -> m a: remote moved to b -> m copying a to b +picked tool 'python ../merge' for a (binary False symlink False) merging a and b my a@e300d1c794ec+ other b@79cc6877a3b7 ancestor a@924404dff337 removing a +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@e300d1c794ec+ other rev@79cc6877a3b7 ancestor rev@924404dff337 0 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -456,8 +493,10 @@ checking for directory renames b: local moved to a -> m rev: versions differ -> m +picked tool 'python ../merge' for b (binary False symlink False) merging b and a my b@ec03c2ca8642+ other a@f4db7e329e71 ancestor a@924404dff337 +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ec03c2ca8642+ other rev@f4db7e329e71 ancestor rev@924404dff337 0 files updated, 2 files merged, 0 files removed, 0 files unresolved @@ -484,9 +523,12 @@ b: local moved to a -> m rev: versions differ -> m c: remote created -> g +picked tool 'python ../merge' for b (binary False symlink False) merging b and a my b@ecf3cb2a4219+ other a@2b958612230f ancestor a@924404dff337 + premerge successful getting c +picked tool 'python ../merge' for rev (binary False symlink False) merging rev my rev@ecf3cb2a4219+ other rev@2b958612230f ancestor rev@924404dff337 1 files updated, 2 files merged, 0 files removed, 0 files unresolved diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-revert --- a/tests/test-revert Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-revert Mon Feb 18 19:21:33 2008 +0100 @@ -1,6 +1,7 @@ #!/bin/sh -hg init +hg init repo +cd repo echo 123 > a echo 123 > c echo 123 > e @@ -27,7 +28,16 @@ hg revert --no-backup c echo %% should show unknown: b hg status -echo %% should show a b c e +hg add b +echo %% should show b added +hg status b +rm b +echo %% should show b deleted +hg status b +hg revert -v b +echo %% should not find b +hg status b +echo %% should show a c e ls echo %% should verbosely save backup to e.orig echo z > e @@ -40,19 +50,26 @@ rm q echo %% should say file not found hg revert notfound +touch d +hg add d hg rm a hg commit -m "second" -d "1000000 0" echo z > z hg add z hg st -echo %% should add a, forget z +echo %% should add a, remove d, forget z hg revert --all -r0 -echo %% should forget a +echo %% should forget a, undelete d hg revert --all -rtip rm a *.orig echo %% should silently add a hg revert -r0 a hg st a +hg rm d +hg st d +echo %% should silently keep d removed +hg revert -r0 d +hg st d hg update -C chmod +x c @@ -68,6 +85,8 @@ echo %% should print executable test -x c && echo executable +cd .. + echo %% issue 241 hg init a cd a @@ -100,3 +119,33 @@ hg revert newa hg st a newa +cd .. + +hg init ignored +cd ignored +echo '^ignored$' > .hgignore +echo '^ignoreddir$' >> .hgignore +echo '^removed$' >> .hgignore + +mkdir ignoreddir +touch ignoreddir/file +touch ignoreddir/removed +touch ignored +touch removed +echo '%% 4 ignored files (we will add/commit everything)' +hg st -A -X .hgignore +hg ci -qAm 'add files' ignored ignoreddir/file ignoreddir/removed removed + +echo >> ignored +echo >> ignoreddir/file +hg rm removed ignoreddir/removed +echo '%% should revert ignored* and undelete *removed' +hg revert -a --no-backup +hg st -mardi + +hg up -qC +echo >> ignored +hg rm removed +echo %% should silently revert the named files +hg revert --no-backup ignored removed +hg st -mardi diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-revert-flags --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-revert-flags Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,17 @@ +#!/bin/sh + +"$TESTDIR/hghave" execbit || exit 80 + +hg init repo +cd repo +echo foo > foo +chmod 644 foo +hg ci -qAm '644' + +chmod 755 foo +hg ci -qAm '755' + +echo '% reverting to rev 0' +hg revert -a -r 0 +hg st +hg diff --git diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-revert-flags.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-revert-flags.out Mon Feb 18 19:21:33 2008 +0100 @@ -0,0 +1,6 @@ +% reverting to rev 0 +reverting foo +M foo +diff --git a/foo b/foo +old mode 100755 +new mode 100644 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-revert.out --- a/tests/test-revert.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-revert.out Mon Feb 18 19:21:33 2008 +0100 @@ -18,16 +18,20 @@ ? b %% should show unknown: b ? b -%% should show a b c e +%% should show b added +A b +%% should show b deleted +! b +forgetting b +%% should not find b +b: No such file or directory +%% should show a c e a -b c e %% should verbosely save backup to e.orig saving current version of e as e.orig reverting e -resolving manifests -getting e %% should say no changes needed no changes needed to a %% should say file not managed @@ -35,16 +39,20 @@ %% should say file not found notfound: No such file in rev 095eacd0c0d7 A z -? b ? e.orig -%% should add a, forget z +%% should add a, remove d, forget z adding a +removing d forgetting z -%% should forget a +%% should forget a, undelete d forgetting a +undeleting d %% should silently add a A a -0 files updated, 0 files merged, 1 files removed, 0 files unresolved +R d +%% should silently keep d removed +R d +1 files updated, 0 files merged, 1 files removed, 0 files unresolved reverting c %% should print non-executable non-executable @@ -65,3 +73,14 @@ reverting b/b % reverting a rename target should revert the source ? newa +%% 4 ignored files (we will add/commit everything) +I ignored +I ignoreddir/file +I ignoreddir/removed +I removed +%% should revert ignored* and undelete *removed +reverting ignored +reverting ignoreddir/file +undeleting ignoreddir/removed +undeleting removed +%% should silently revert the named files diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-rollback --- a/tests/test-rollback Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-rollback Mon Feb 18 19:21:33 2008 +0100 @@ -14,8 +14,15 @@ hg parents hg status -# Test issue 902 +echo % Test issue 902 hg commit -m "test" hg branch test hg rollback hg branch + +echo % Test rollback of hg before issue 902 was fixed +hg commit -m "test" +hg branch test +rm .hg/undo.branch +hg rollback +hg branch diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-rollback.out --- a/tests/test-rollback.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-rollback.out Mon Feb 18 19:21:33 2008 +0100 @@ -16,6 +16,12 @@ checking files 0 files, 0 changesets, 0 total revisions A a +% Test issue 902 marked working directory as branch test rolling back last transaction default +% Test rollback of hg before issue 902 was fixed +marked working directory as branch test +rolling back last transaction +Named branch could not be reset, current branch still is: test +test diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-serve --- a/tests/test-serve Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-serve Mon Feb 18 19:21:33 2008 +0100 @@ -16,24 +16,28 @@ echo % With -v hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid -v | sed -e 's,:[0-9][0-9]*/,/,' cat hg.pid >> "$DAEMON_PIDS" +sleep 1 kill `cat hg.pid` sleep 1 echo % With --prefix foo hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid -v --prefix foo | sed -e 's,:[0-9][0-9]*/,/,' cat hg.pid >> "$DAEMON_PIDS" +sleep 1 kill `cat hg.pid` sleep 1 echo % With --prefix /foo hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid -v --prefix /foo | sed -e 's,:[0-9][0-9]*/,/,' cat hg.pid >> "$DAEMON_PIDS" +sleep 1 kill `cat hg.pid` sleep 1 echo % With --prefix foo/ hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid -v --prefix foo/ | sed -e 's,:[0-9][0-9]*/,/,' cat hg.pid >> "$DAEMON_PIDS" +sleep 1 kill `cat hg.pid` sleep 1 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-serve.out --- a/tests/test-serve.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-serve.out Mon Feb 18 19:21:33 2008 +0100 @@ -2,15 +2,11 @@ access log created - .hg/hgrc respected % With -v listening at http://localhost/ -killed! % With --prefix foo listening at http://localhost/foo/ -killed! % With --prefix /foo listening at http://localhost/foo/ -killed! % With --prefix foo/ listening at http://localhost/foo/ -killed! % With --prefix /foo/ listening at http://localhost/foo/ diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-simplemerge.py --- a/tests/test-simplemerge.py Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-simplemerge.py Mon Feb 18 19:21:33 2008 +0100 @@ -19,14 +19,24 @@ from unittest import TestCase import imp import shutil -from mercurial import util +from mercurial import util, simplemerge + +# bzr compatible interface, for the tests +class Merge3(simplemerge.Merge3Text): + """3-way merge of texts. -# copy simplemerge to the cwd to avoid creating a .pyc file in the source tree -shutil.copyfile(os.path.join(os.environ['TESTDIR'], os.path.pardir, - 'contrib', 'simplemerge'), - 'simplemerge.py') -simplemerge = imp.load_source('simplemerge', 'simplemerge.py') -Merge3 = simplemerge.Merge3 + Given BASE, OTHER, THIS, tries to produce a combined text + incorporating the changes from both BASE->OTHER and BASE->THIS. + All three will typically be sequences of lines.""" + def __init__(self, base, a, b): + basetext = '\n'.join([i.strip('\n') for i in base] + ['']) + atext = '\n'.join([i.strip('\n') for i in a] + ['']) + btext = '\n'.join([i.strip('\n') for i in b] + ['']) + if util.binary(basetext) or util.binary(atext) or util.binary(btext): + raise util.Abort("don't know how to merge binary files") + simplemerge.Merge3Text.__init__(self, basetext, atext, btext, + base, a, b) + CantReprocessAndShowBase = simplemerge.CantReprocessAndShowBase def split_lines(t): diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-ssh --- a/tests/test-ssh Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-ssh Mon Feb 18 19:21:33 2008 +0100 @@ -27,6 +27,11 @@ sys.exit(bool(r)) EOF +cat < badhook +import sys +sys.stdout.write("KABOOM") +EOF + echo "# creating 'remote'" hg init remote cd remote @@ -91,13 +96,16 @@ echo z > z hg ci -A -m z -d '1000001 0' z +# a bad, evil hook that prints to stdout +echo 'changegroup.stdout = python ../badhook' >> .hg/hgrc cd ../local echo r > r hg ci -A -m z -d '1000002 0' r -echo "# push should succeed" +echo "# push should succeed even though it has an unexpected response" hg push +hg -R ../remote heads cd .. cat dummylog diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-ssh.out --- a/tests/test-ssh.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-ssh.out Mon Feb 18 19:21:33 2008 +0100 @@ -70,7 +70,7 @@ checking files 2 files, 2 changesets, 3 total revisions bleah -# push should succeed +# push should succeed even though it has an unexpected response pushing to ssh://user@dummy/remote searching for changes note: unsynced remote changes! @@ -78,6 +78,21 @@ remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files +abort: unexpected response: +'KABOOM1\n' +changeset: 3:ac7448082955 +tag: tip +parent: 1:572896fe480d +user: test +date: Mon Jan 12 13:46:42 1970 +0000 +summary: z + +changeset: 2:187c6caa0d1e +parent: 0:e34318c26897 +user: test +date: Mon Jan 12 13:46:41 1970 +0000 +summary: z + Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio Got arguments 1:user@dummy 2:hg -R remote serve --stdio Got arguments 1:user@dummy 2:hg -R remote serve --stdio diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-static-http --- a/tests/test-static-http Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-static-http Mon Feb 18 19:21:33 2008 +0100 @@ -63,4 +63,19 @@ cat a hg paths | sed -e 's,:[0-9][0-9]*/,/,' +echo '% test with empty repo (issue965)' +cd .. +hg init remotempty + +http_proxy= hg clone static-http://localhost:$HGPORT/remotempty local3 | sed -e 's,:[0-9][0-9]*/,/,' + +cd local3 +hg verify +hg paths | sed -e 's,:[0-9][0-9]*/,/,' + +echo '% test with non-repo' +cd .. +mkdir notarepo +http_proxy= hg clone static-http://localhost:$HGPORT/notarepo local3 2>&1 | sed -e 's,:[0-9][0-9]*/,/,' + kill $! diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-static-http.out --- a/tests/test-static-http.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-static-http.out Mon Feb 18 19:21:33 2008 +0100 @@ -42,3 +42,14 @@ 1 files, 1 changesets, 1 total revisions a default = static-http://localhost/ +% test with empty repo (issue965) +no changes found +0 files updated, 0 files merged, 0 files removed, 0 files unresolved +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +0 files, 0 changesets, 0 total revisions +default = static-http://localhost/remotempty +% test with non-repo +abort: 'http://localhost/notarepo' does not appear to be an hg repository! diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-status --- a/tests/test-status Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-status Mon Feb 18 19:21:33 2008 +0100 @@ -21,7 +21,7 @@ hg init repo2 cd repo2 touch modified removed deleted ignored -echo "ignored" > .hgignore +echo "^ignored$" > .hgignore hg ci -A -m 'initial checkin' -d "1000000 0" sleep 1 # make sure mtime is changed touch modified added unknown ignored @@ -37,3 +37,10 @@ hg status -C echo "hg status -A:" hg status -A +echo "^ignoreddir$" > .hgignore +mkdir ignoreddir +touch ignoreddir/file +echo "hg status ignoreddir/file:" +hg status ignoreddir/file +echo "hg status -i ignoreddir/file:" +hg status -i ignoreddir/file diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-status.out --- a/tests/test-status.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-status.out Mon Feb 18 19:21:33 2008 +0100 @@ -99,7 +99,6 @@ A added R removed ! deleted -? ignored ? unknown hg status -C: A added @@ -118,3 +117,6 @@ I ignored C .hgignore C modified +hg status ignoreddir/file: +hg status -i ignoreddir/file: +I ignoreddir/file diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-symlink-basic --- a/tests/test-symlink-basic Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-symlink-basic Mon Feb 18 19:21:33 2008 +0100 @@ -2,17 +2,12 @@ "$TESTDIR/hghave" symlink || exit 80 -cleanpath() -{ - sed -e "s:/.*\(/test-symlink-basic/.*\):...\1:" -} - hg init a cd a ln -s nothing dangling -hg commit -m 'commit symlink without adding' -d '0 0' dangling 2>&1 | cleanpath +hg commit -m 'commit symlink without adding' dangling hg add dangling -hg commit -m 'add symlink' -d '0 0' +hg commit -m 'add symlink' hg tip -v hg manifest --debug diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-symlink-basic.out --- a/tests/test-symlink-basic.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-symlink-basic.out Mon Feb 18 19:21:33 2008 +0100 @@ -1,4 +1,4 @@ -abort: file .../test-symlink-basic/a/dangling not tracked! +abort: file dangling not tracked! changeset: 0:cabd88b706fc tag: tip user: test diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-up-local-change.out --- a/tests/test-up-local-change.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-up-local-change.out Mon Feb 18 19:21:33 2008 +0100 @@ -22,6 +22,7 @@ b a: versions differ -> m b: remote created -> g +picked tool 'true' for a (binary False symlink False) merging a my a@33aaa84a386b+ other a@802f095af299 ancestor a@33aaa84a386b getting b @@ -58,6 +59,7 @@ b a: versions differ -> m b: remote created -> g +picked tool 'true' for a (binary False symlink False) merging a my a@33aaa84a386b+ other a@802f095af299 ancestor a@33aaa84a386b getting b @@ -109,8 +111,10 @@ searching for copies back to rev 1 a: versions differ -> m b: versions differ -> m +picked tool 'true' for a (binary False symlink False) merging a my a@802f095af299+ other a@030602aee63d ancestor a@33aaa84a386b +picked tool 'true' for b (binary False symlink False) merging b my b@802f095af299+ other b@030602aee63d ancestor b@000000000000 0 files updated, 2 files merged, 0 files removed, 0 files unresolved diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-walk --- a/tests/test-walk Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-walk Mon Feb 18 19:21:33 2008 +0100 @@ -93,6 +93,13 @@ debugwalk fenugreek touch new debugwalk new + +mkdir ignored +touch ignored/file +echo '^ignored$' > .hgignore +debugwalk ignored +debugwalk ignored/file + chdir .. debugwalk -R t t/mammals/skunk mkdir t2 diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-walk.out --- a/tests/test-walk.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-walk.out Mon Feb 18 19:21:33 2008 +0100 @@ -283,6 +283,11 @@ hg debugwalk new f new new exact +hg debugwalk ignored + +hg debugwalk ignored/file +f ignored/file ignored/file exact + cd .. hg debugwalk -R t t/mammals/skunk diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-webraw --- a/tests/test-webraw Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-webraw Mon Feb 18 19:21:33 2008 +0100 @@ -2,17 +2,18 @@ hg init test cd test -cat >sometext.txt <'sub/some "text".txt' <> $DAEMON_PIDS -("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?f=f165dc289438;file=sometext.txt;style=raw' content-type content-length content-disposition) >getoutput.txt & +("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw' content-type content-length content-disposition) >getoutput.txt & sleep 5 kill `cat hg.pid` diff -r 90e5c82a3859 -r 50a277e6ceae tests/test-webraw.out --- a/tests/test-webraw.out Mon Feb 18 19:20:22 2008 +0100 +++ b/tests/test-webraw.out Mon Feb 18 19:21:33 2008 +0100 @@ -1,10 +1,10 @@ 200 Script output follows content-type: text/plain content-length: 157 -content-disposition: inline; filename=sometext.txt +content-disposition: inline; filename="some \"text\".txt" This is just some random text that will go inside the file and take a few lines. It is very boring to read, but computers don't care about things like that. -host - - [date] "GET /?f=f165dc289438;file=sometext.txt;style=raw HTTP/1.1" 200 - +host - - [date] "GET /?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw HTTP/1.1" 200 -