Mercurial > hg
changeset 13122:4a13ca2c21ce
merge with stable
author | Benoit Boissinot <benoit.boissinot@ens-lyon.org> |
---|---|
date | Fri, 10 Dec 2010 23:05:48 +0100 |
parents | 5dac0d04b838 (diff) 2245fcd0e160 (current diff) |
children | e76701bf4480 |
files | mercurial/subrepo.py |
diffstat | 63 files changed, 2050 insertions(+), 740 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Fri Dec 10 01:30:16 2010 +0100 +++ b/Makefile Fri Dec 10 23:05:48 2010 +0100 @@ -45,7 +45,7 @@ clean: -$(PYTHON) setup.py clean --all # ignore errors from this command find . \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';' - rm -f MANIFEST mercurial/__version__.py tests/*.err + rm -f MANIFEST tests/*.err rm -rf build mercurial/locale $(MAKE) -C doc clean
--- a/contrib/check-code.py Fri Dec 10 01:30:16 2010 +0100 +++ b/contrib/check-code.py Fri Dec 10 23:05:48 2010 +0100 @@ -8,6 +8,7 @@ # GNU General Public License version 2 or any later version. import re, glob, os, sys +import keyword import optparse def repquote(m): @@ -64,6 +65,7 @@ ('^([^"\']|("[^"]*")|(\'[^\']*\'))*\\^', "^ must be quoted"), (r'^source\b', "don't use 'source', use '.'"), (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"), + (r'ls\s+[^-]+\s+-', "options to 'ls' must come before filenames"), ] testfilters = [ @@ -117,8 +119,8 @@ (r'^\s*(if|while|def|class|except|try)\s[^[]*:\s*[^\]#\s]+', "linebreak after :"), (r'class\s[^(]:', "old-style class, use class foo(object)"), - (r'^\s+del\(', "del isn't a function"), - (r'^\s+except\(', "except isn't a function"), + (r'\b(%s)\(' % '|'.join(keyword.kwlist), + "Python keyword is not a function"), (r',]', "unneeded trailing ',' in list"), # (r'class\s[A-Z][^\(]*\((?!Exception)', # "don't capitalize non-exception classes"), @@ -132,6 +134,8 @@ (r'(?<!def)\s+(callable)\(', "callable not available in Python 3, use hasattr(f, '__call__')"), (r'if\s.*\selse', "if ... else form not available in Python 2.4"), + (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist), + "gratuitous whitespace after Python keyword"), (r'([\(\[]\s\S)|(\S\s[\)\]])', "gratuitous whitespace in () or []"), # (r'\s\s=', "gratuitous whitespace before ="), (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', @@ -145,6 +149,9 @@ (r'raise Exception', "don't raise generic exceptions"), (r'ui\.(status|progress|write|note|warn)\([\'\"]x', "warning: unwrapped ui message"), + (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"), + (r' [=!]=\s+(True|False|None)', + "comparison with singleton, use 'is' or 'is not' instead"), ] pyfilters = [
--- a/doc/Makefile Fri Dec 10 01:30:16 2010 +0100 +++ b/doc/Makefile Fri Dec 10 23:05:48 2010 +0100 @@ -1,11 +1,13 @@ SOURCES=$(wildcard *.[0-9].txt) MAN=$(SOURCES:%.txt=%) HTML=$(SOURCES:%.txt=%.html) -GENDOC=gendoc.py ../mercurial/commands.py ../mercurial/help.py ../mercurial/help/*.txt +GENDOC=gendoc.py ../mercurial/commands.py ../mercurial/help.py \ + ../mercurial/help/*.txt ../hgext/*.py ../hgext/*/__init__.py PREFIX=/usr/local MANDIR=$(PREFIX)/share/man INSTALL=install -c -m 644 PYTHON=python +RSTARGS= export LANGUAGE=C export LC_ALL=C @@ -24,11 +26,11 @@ mv $@.tmp $@ %: %.txt common.txt - $(PYTHON) runrst hgmanpage --halt warning \ + $(PYTHON) runrst hgmanpage $(RSTARGS) --halt warning \ --strip-elements-with-class htmlonly $*.txt $* %.html: %.txt common.txt - $(PYTHON) runrst html --halt warning \ + $(PYTHON) runrst html $(RSTARGS) --halt warning \ --link-stylesheet --stylesheet-path style.css $*.txt $*.html MANIFEST: man html
--- a/doc/gendoc.py Fri Dec 10 01:30:16 2010 +0100 +++ b/doc/gendoc.py Fri Dec 10 23:05:48 2010 +0100 @@ -40,7 +40,7 @@ if longopt: allopts.append("--%s" % longopt) desc += default and _(" (default: %s)") % default or "" - yield(", ".join(allopts), desc) + yield (", ".join(allopts), desc) def get_cmd(cmd, cmdtable): d = {}
--- a/hgext/bookmarks.py Fri Dec 10 01:30:16 2010 +0100 +++ b/hgext/bookmarks.py Fri Dec 10 23:05:48 2010 +0100 @@ -31,7 +31,7 @@ from mercurial.i18n import _ from mercurial.node import nullid, nullrev, bin, hex, short from mercurial import util, commands, repair, extensions, pushkey, hg, url -from mercurial import revset +from mercurial import revset, encoding import os def write(repo): @@ -58,7 +58,7 @@ try: file = repo.opener('bookmarks', 'w', atomictemp=True) for refspec, node in refs.iteritems(): - file.write("%s %s\n" % (hex(node), refspec)) + file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec))) file.rename() # touch 00changelog.i so hgweb reloads bookmarks (no lock needed) @@ -143,7 +143,7 @@ write(repo) return - if mark != None: + if mark is not None: if "\n" in mark: raise util.Abort(_("bookmark name cannot contain newlines")) mark = mark.strip() @@ -239,6 +239,7 @@ bookmarks = {} for line in self.opener('bookmarks'): sha, refspec = line.strip().split(' ', 1) + refspec = encoding.tolocal(refspec) bookmarks[refspec] = self.changelog.lookup(sha) except: pass @@ -339,7 +340,7 @@ rb = remote.listkeys('bookmarks') for k in rb.keys(): if k in self._bookmarks: - nr, nl = rb[k], self._bookmarks[k] + nr, nl = rb[k], hex(self._bookmarks[k]) if nr in self: cr = self[nr] cl = self[nl] @@ -354,14 +355,12 @@ return result def addchangegroup(self, *args, **kwargs): - parents = self.dirstate.parents() - result = super(bookmark_repo, self).addchangegroup(*args, **kwargs) if result > 1: # We have more heads than before return result node = self.changelog.tip() - + parents = self.dirstate.parents() self._bookmarksupdate(parents, node) return result
--- a/hgext/convert/__init__.py Fri Dec 10 01:30:16 2010 +0100 +++ b/hgext/convert/__init__.py Fri Dec 10 23:05:48 2010 +0100 @@ -59,10 +59,10 @@ --sourcesort try to preserve source revisions order, only supported by Mercurial sources. - If <REVMAP> isn't given, it will be put in a default location - (<dest>/.hg/shamap by default). The <REVMAP> is a simple text file - that maps each source commit ID to the destination ID for that - revision, like so:: + If ``REVMAP`` isn't given, it will be put in a default location + (``<dest>/.hg/shamap`` by default). The ``REVMAP`` is a simple + text file that maps each source commit ID to the destination ID + for that revision, like so:: <source ID> <destination ID> @@ -138,15 +138,19 @@ Mercurial Source '''''''''''''''' - --config convert.hg.ignoreerrors=False (boolean) - ignore integrity errors when reading. Use it to fix Mercurial - repositories with missing revlogs, by converting from and to - Mercurial. - --config convert.hg.saverev=False (boolean) - store original revision ID in changeset (forces target IDs to - change) - --config convert.hg.startrev=0 (hg revision identifier) - convert start revision and its descendants + The Mercurial source recognizes the following configuration + options, which you can set on the command line with ``--config``: + + :convert.hg.ignoreerrors: ignore integrity errors when reading. + Use it to fix Mercurial repositories with missing revlogs, by + converting from and to Mercurial. Default is False. + + :convert.hg.saverev: store original. revision ID in changeset + (forces target IDs to change). It takes and boolean argument + and defaults to False. + + :convert.hg.startrev: convert start revision and its descendants. + It takes a hg revision identifier and defaults to 0. CVS Source '''''''''' @@ -154,42 +158,46 @@ CVS source will use a sandbox (i.e. a checked-out copy) from CVS to indicate the starting point of what will be converted. Direct access to the repository files is not needed, unless of course the - repository is :local:. The conversion uses the top level directory - in the sandbox to find the CVS repository, and then uses CVS rlog - commands to find files to convert. This means that unless a - filemap is given, all files under the starting directory will be + repository is ``:local:``. The conversion uses the top level + directory in the sandbox to find the CVS repository, and then uses + CVS rlog commands to find files to convert. This means that unless + a filemap is given, all files under the starting directory will be converted, and that any directory reorganization in the CVS sandbox is ignored. - The options shown are the defaults. + The following options can be used with ``--config``: + + :convert.cvsps.cache: Set to False to disable remote log caching, + for testing and debugging purposes. Default is True. + + :convert.cvsps.fuzz: Specify the maximum time (in seconds) that is + allowed between commits with identical user and log message in + a single changeset. When very large files were checked in as + part of a changeset then the default may not be long enough. + The default is 60. - --config convert.cvsps.cache=True (boolean) - Set to False to disable remote log caching, for testing and - debugging purposes. - --config convert.cvsps.fuzz=60 (integer) - Specify the maximum time (in seconds) that is allowed between - commits with identical user and log message in a single - changeset. When very large files were checked in as part of a - changeset then the default may not be long enough. - --config convert.cvsps.mergeto='{{mergetobranch ([-\\w]+)}}' - Specify a regular expression to which commit log messages are - matched. If a match occurs, then the conversion process will - insert a dummy revision merging the branch on which this log - message occurs to the branch indicated in the regex. - --config convert.cvsps.mergefrom='{{mergefrombranch ([-\\w]+)}}' - Specify a regular expression to which commit log messages are - matched. If a match occurs, then the conversion process will - add the most recent revision on the branch indicated in the - regex as the second parent of the changeset. - --config hook.cvslog - Specify a Python function to be called at the end of gathering - the CVS log. The function is passed a list with the log entries, - and can modify the entries in-place, or add or delete them. - --config hook.cvschangesets - Specify a Python function to be called after the changesets - are calculated from the the CVS log. The function is passed - a list with the changeset entries, and can modify the changesets - in-place, or add or delete them. + :convert.cvsps.mergeto: Specify a regular expression to which + commit log messages are matched. If a match occurs, then the + conversion process will insert a dummy revision merging the + branch on which this log message occurs to the branch + indicated in the regex. Default is ``{{mergetobranch + ([-\\w]+)}}`` + + :convert.cvsps.mergefrom: Specify a regular expression to which + commit log messages are matched. If a match occurs, then the + conversion process will add the most recent revision on the + branch indicated in the regex as the second parent of the + changeset. Default is ``{{mergefrombranch ([-\\w]+)}}`` + + :hook.cvslog: Specify a Python function to be called at the end of + gathering the CVS log. The function is passed a list with the + log entries, and can modify the entries in-place, or add or + delete them. + + :hook.cvschangesets: Specify a Python function to be called after + the changesets are calculated from the the CVS log. The + function is passed a list with the changeset entries, and can + modify the changesets in-place, or add or delete them. An additional "debugcvsps" Mercurial command allows the builtin changeset merging code to be run without doing a conversion. Its @@ -200,29 +208,33 @@ ''''''''''''''''' Subversion source detects classical trunk/branches/tags layouts. - By default, the supplied "svn://repo/path/" source URL is - converted as a single branch. If "svn://repo/path/trunk" exists it - replaces the default branch. If "svn://repo/path/branches" exists, - its subdirectories are listed as possible branches. If - "svn://repo/path/tags" exists, it is looked for tags referencing - converted branches. Default "trunk", "branches" and "tags" values - can be overridden with following options. Set them to paths + By default, the supplied ``svn://repo/path/`` source URL is + converted as a single branch. If ``svn://repo/path/trunk`` exists + it replaces the default branch. If ``svn://repo/path/branches`` + exists, its subdirectories are listed as possible branches. If + ``svn://repo/path/tags`` exists, it is looked for tags referencing + converted branches. Default ``trunk``, ``branches`` and ``tags`` + values can be overridden with following options. Set them to paths relative to the source URL, or leave them blank to disable auto detection. - --config convert.svn.branches=branches (directory name) - specify the directory containing branches - --config convert.svn.tags=tags (directory name) - specify the directory containing tags - --config convert.svn.trunk=trunk (directory name) - specify the name of the trunk branch + The following options can be set with ``--config``: + + :convert.svn.branches: specify the directory containing branches. + The defaults is ``branches``. + + :convert.svn.tags: specify the directory containing tags. The + default is ``tags``. + + :convert.svn.trunk: specify the name of the trunk branch The + defauls is ``trunk``. Source history can be retrieved starting at a specific revision, instead of being integrally converted. Only single branch conversions are supported. - --config convert.svn.startrev=0 (svn revision number) - specify start Subversion revision. + :convert.svn.startrev: specify start Subversion revision number. + The default is 0. Perforce Source ''''''''''''''' @@ -232,24 +244,27 @@ source to a flat Mercurial repository, ignoring labels, branches and integrations. Note that when a depot path is given you then usually should specify a target directory, because otherwise the - target may be named ...-hg. + target may be named ``...-hg``. It is possible to limit the amount of source history to be - converted by specifying an initial Perforce revision. + converted by specifying an initial Perforce revision: - --config convert.p4.startrev=0 (perforce changelist number) - specify initial Perforce revision. + :convert.p4.startrev: specify initial Perforce revision, a + Perforce changelist number). Mercurial Destination ''''''''''''''''''''' - --config convert.hg.clonebranches=False (boolean) - dispatch source branches in separate clones. - --config convert.hg.tagsbranch=default (branch name) - tag revisions branch name - --config convert.hg.usebranchnames=True (boolean) - preserve branch names + The following options are supported: + + :convert.hg.clonebranches: dispatch source branches in separate + clones. The default is False. + :convert.hg.tagsbranch: branch name for tag revisions, defaults to + ``default``. + + :convert.hg.usebranchnames: preserve branch names. The default is + True """ return convcmd.convert(ui, src, dest, revmapfile, **opts)
--- a/hgext/eol.py Fri Dec 10 01:30:16 2010 +0100 +++ b/hgext/eol.py Fri Dec 10 23:05:48 2010 +0100 @@ -61,6 +61,11 @@ Such files are normally not touched under the assumption that they have mixed EOLs on purpose. +The extension provides ``cleverencode:`` and ``cleverdecode:`` filters +like the deprecated win32text extension does. This means that you can +disable win32text and enable eol and your filters will still work. You +only need to these filters until you have prepared a ``.hgeol`` file. + The ``win32text.forbid*`` hooks provided by the win32text extension have been unified into a single hook named ``eol.hook``. The hook will lookup the expected line endings from the ``.hgeol`` file, which means @@ -109,6 +114,9 @@ 'to-lf': tolf, 'to-crlf': tocrlf, 'is-binary': isbinary, + # The following provide backwards compatibility with win32text + 'cleverencode:': tolf, + 'cleverdecode:': tocrlf }
--- a/hgext/hgk.py Fri Dec 10 01:30:16 2010 +0100 +++ b/hgext/hgk.py Fri Dec 10 23:05:48 2010 +0100 @@ -181,14 +181,14 @@ if i + x >= count: l[chunk - x:] = [0] * (chunk - x) break - if full != None: + if full is not None: l[x] = repo[i + x] l[x].changeset() # force reading else: l[x] = 1 for x in xrange(chunk - 1, -1, -1): if l[x] != 0: - yield (i + x, full != None and l[x] or None) + yield (i + x, full is not None and l[x] or None) if i == 0: break
--- a/hgext/keyword.py Fri Dec 10 01:30:16 2010 +0100 +++ b/hgext/keyword.py Fri Dec 10 23:05:48 2010 +0100 @@ -101,6 +101,14 @@ # names of extensions using dorecord recordextensions = 'record' +colortable = { + 'kwfiles.enabled': 'green bold', + 'kwfiles.deleted': 'cyan bold underline', + 'kwfiles.enabledunknown': 'green', + 'kwfiles.ignored': 'bold', + 'kwfiles.ignoredunknown': 'none' +} + # date like in cvs' $Date utcdate = lambda x: util.datestr((x[0], 0), '%Y/%m/%d %H:%M:%S') # date like in svn's $Date @@ -111,7 +119,6 @@ # make keyword tools accessible kwtools = {'templater': None, 'hgcmd': ''} - def _defaultkwmaps(ui): '''Returns default keywordmaps according to keywordset configuration.''' templates = { @@ -170,14 +177,25 @@ for k, v in kwmaps) else: self.templates = _defaultkwmaps(self.ui) - escaped = '|'.join(map(re.escape, self.templates.keys())) - self.re_kw = re.compile(r'\$(%s)\$' % escaped) - self.re_kwexp = re.compile(r'\$(%s): [^$\n\r]*? \$' % escaped) - templatefilters.filters.update({'utcdate': utcdate, 'svnisodate': svnisodate, 'svnutcdate': svnutcdate}) + @util.propertycache + def escape(self): + '''Returns bar-separated and escaped keywords.''' + return '|'.join(map(re.escape, self.templates.keys())) + + @util.propertycache + def rekw(self): + '''Returns regex for unexpanded keywords.''' + return re.compile(r'\$(%s)\$' % self.escape) + + @util.propertycache + def rekwexp(self): + '''Returns regex for expanded keywords.''' + return re.compile(r'\$(%s): [^$\n\r]*? \$' % self.escape) + def substitute(self, data, path, ctx, subfunc): '''Replaces keywords in data with expanded template.''' def kwsub(mobj): @@ -191,11 +209,15 @@ return '$%s: %s $' % (kw, ekw) return subfunc(kwsub, data) + def linkctx(self, path, fileid): + '''Similar to filelog.linkrev, but returns a changectx.''' + return self.repo.filectx(path, fileid=fileid).changectx() + def expand(self, path, node, data): '''Returns data with keywords expanded.''' if not self.restrict and self.match(path) and not util.binary(data): - ctx = self.repo.filectx(path, fileid=node).changectx() - return self.substitute(data, path, ctx, self.re_kw.sub) + ctx = self.linkctx(path, node) + return self.substitute(data, path, ctx, self.rekw.sub) return data def iskwfile(self, cand, ctx): @@ -212,8 +234,8 @@ kwcmd = self.restrict and lookup # kwexpand/kwshrink if self.restrict or expand and lookup: mf = ctx.manifest() - fctx = ctx - subn = (self.restrict or rekw) and self.re_kw.subn or self.re_kwexp.subn + lctx = ctx + re_kw = (self.restrict or rekw) and self.rekw or self.rekwexp msg = (expand and _('overwriting %s expanding keywords\n') or _('overwriting %s shrinking keywords\n')) for f in candidates: @@ -225,12 +247,12 @@ continue if expand: if lookup: - fctx = self.repo.filectx(f, fileid=mf[f]).changectx() - data, found = self.substitute(data, f, fctx, subn) + lctx = self.linkctx(f, mf[f]) + data, found = self.substitute(data, f, lctx, re_kw.subn) elif self.restrict: - found = self.re_kw.search(data) + found = re_kw.search(data) else: - data, found = _shrinktext(data, subn) + data, found = _shrinktext(data, re_kw.subn) if found: self.ui.note(msg % f) self.repo.wwrite(f, data, ctx.flags(f)) @@ -242,7 +264,7 @@ def shrink(self, fname, text): '''Returns text with all keyword substitutions removed.''' if self.match(fname) and not util.binary(text): - return _shrinktext(text, self.re_kwexp.sub) + return _shrinktext(text, self.rekwexp.sub) return text def shrinklines(self, fname, lines): @@ -250,7 +272,7 @@ if self.match(fname): text = ''.join(lines) if not util.binary(text): - return _shrinktext(text, self.re_kwexp.sub).splitlines(True) + return _shrinktext(text, self.rekwexp.sub).splitlines(True) return lines def wread(self, fname, data): @@ -424,18 +446,21 @@ files = sorted(modified + added + clean) wctx = repo[None] kwfiles = kwt.iskwfile(files, wctx) + kwdeleted = kwt.iskwfile(deleted, wctx) kwunknown = kwt.iskwfile(unknown, wctx) if not opts.get('ignore') or opts.get('all'): - showfiles = kwfiles, kwunknown + showfiles = kwfiles, kwdeleted, kwunknown else: - showfiles = [], [] + showfiles = [], [], [] if opts.get('all') or opts.get('ignore'): showfiles += ([f for f in files if f not in kwfiles], [f for f in unknown if f not in kwunknown]) - for char, filenames in zip('KkIi', showfiles): + kwlabels = 'enabled deleted enabledunknown ignored ignoredunknown'.split() + kwstates = zip('K!kIi', showfiles, kwlabels) + for char, filenames, kwstate in kwstates: fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n' for f in filenames: - ui.write(fmt % repo.pathto(f, cwd)) + ui.write(fmt % repo.pathto(f, cwd), label='kwfiles.' + kwstate) def shrink(ui, repo, *pats, **opts): '''revert expanded keywords in the working directory
--- a/hgext/mq.py Fri Dec 10 01:30:16 2010 +0100 +++ b/hgext/mq.py Fri Dec 10 23:05:48 2010 +0100 @@ -1006,7 +1006,7 @@ raise util.Abort(_("patch %s not in series") % patch) def push(self, repo, patch=None, force=False, list=False, - mergeq=None, all=False, move=False): + mergeq=None, all=False, move=False, exact=False): diffopts = self.diffopts() wlock = repo.wlock() try: @@ -1015,7 +1015,7 @@ heads += ls if not heads: heads = [nullid] - if repo.dirstate.parents()[0] not in heads: + if repo.dirstate.parents()[0] not in heads and not exact: self.ui.status(_("(working directory not at a head)\n")) if not self.series: @@ -1062,9 +1062,21 @@ if not force: self.check_localchanges(repo) + if exact: + if move: + raise util.Abort(_("cannot use --exact and --move together")) + if self.applied: + raise util.Abort(_("cannot push --exact with applied patches")) + root = self.series[start] + target = patchheader(self.join(root), self.plainmode).parent + if not target: + raise util.Abort(_("%s does not have a parent recorded" % root)) + if not repo[target] == repo['.']: + hg.update(repo, target) + if move: if not patch: - raise util.Abort(_("please specify the patch to move")) + raise util.Abort(_("please specify the patch to move")) for i, rpn in enumerate(self.full_series[start:]): # strip markers for patch guards if self.guard_re.split(rpn, 1)[0] == patch: @@ -1270,10 +1282,10 @@ # and then commit. # # this should really read: - # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4] + # mm, dd, aa = repo.status(top, patchparent)[:3] # but we do it backwards to take advantage of manifest/chlog # caching against the next repo.status call - mm, aa, dd, aa2 = repo.status(patchparent, top)[:4] + mm, aa, dd = repo.status(patchparent, top)[:3] changes = repo.changelog.read(top) man = repo.manifest.read(changes[0]) aaa = aa[:] @@ -1289,6 +1301,9 @@ else: match = cmdutil.matchall(repo) m, a, r, d = repo.status(match=match)[:4] + mm = set(mm) + aa = set(aa) + dd = set(dd) # we might end up with files that were added between # qtip and the dirstate parent, but then changed in the @@ -1299,7 +1314,7 @@ self.ui.warn(_('warning: not refreshing %s\n') % x) continue if x not in aa: - mm.append(x) + mm.add(x) # we might end up with files added by the local dirstate that # were deleted by the patch. In this case, they should only # show up in the changed section. @@ -1308,10 +1323,10 @@ self.ui.warn(_('warning: not adding %s\n') % x) continue if x in dd: - del dd[dd.index(x)] - mm.append(x) + dd.remove(x) + mm.add(x) else: - aa.append(x) + aa.add(x) # make sure any files deleted in the local dirstate # are not in the add or change column of the patch forget = [] @@ -1320,16 +1335,16 @@ self.ui.warn(_('warning: not removing %s\n') % x) continue if x in aa: - del aa[aa.index(x)] + aa.remove(x) forget.append(x) continue - elif x in mm: - del mm[mm.index(x)] - dd.append(x) - - m = list(set(mm)) - r = list(set(dd)) - a = list(set(aa)) + else: + mm.discard(x) + dd.add(x) + + m = list(mm) + r = list(dd) + a = list(aa) c = [filter(matchfn, l) for l in (m, a, r)] match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2])) chunks = patch.diff(repo, patchparent, match=match, @@ -1529,7 +1544,7 @@ l = line.rstrip() l = l[10:].split(' ') qpp = [bin(x) for x in l] - elif datastart != None: + elif datastart is not None: l = line.rstrip() n, name = l.split(':', 1) if n: @@ -2344,7 +2359,8 @@ mergeq = queue(ui, repo.join(""), newpath) ui.warn(_("merging with queue at: %s\n") % mergeq.path) ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'), - mergeq=mergeq, all=opts.get('all'), move=opts.get('move')) + mergeq=mergeq, all=opts.get('all'), move=opts.get('move'), + exact=opts.get('exact')) return ret def pop(ui, repo, patch=None, **opts): @@ -3120,6 +3136,7 @@ "^qpush": (push, [('f', 'force', None, _('apply on top of local changes')), + ('e', 'exact', None, _('apply the target patch to its recorded parent')), ('l', 'list', None, _('list patch name in commit text')), ('a', 'all', None, _('apply all patches')), ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
--- a/hgext/record.py Fri Dec 10 01:30:16 2010 +0100 +++ b/hgext/record.py Fri Dec 10 23:05:48 2010 +0100 @@ -10,7 +10,7 @@ from mercurial.i18n import gettext, _ from mercurial import cmdutil, commands, extensions, hg, mdiff, patch from mercurial import util -import copy, cStringIO, errno, os, re, tempfile +import copy, cStringIO, errno, os, re, shutil, tempfile lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)') @@ -344,10 +344,10 @@ # new hunk if resp_file[0] is None and resp_all[0] is None: chunk.pretty(ui) - r = total == 1 and prompt(_('record this change to %r?') % - chunk.filename()) \ - or prompt(_('record change %d/%d to %r?') % - (pos, total, chunk.filename())) + r = (total == 1 + and prompt(_('record this change to %r?') % chunk.filename()) + or prompt(_('record change %d/%d to %r?') % + (pos, total, chunk.filename()))) if r: if fixoffset: chunk = copy.copy(chunk) @@ -429,7 +429,7 @@ merge = len(repo[None].parents()) > 1 if merge: raise util.Abort(_('cannot partially commit a merge ' - '(use hg commit instead)')) + '(use "hg commit" instead)')) changes = repo.status(match=match)[:3] diffopts = mdiff.diffopts(git=True, nodates=True) @@ -475,6 +475,7 @@ os.close(fd) ui.debug('backup %r as %r\n' % (f, tmpname)) util.copyfile(repo.wjoin(f), tmpname) + shutil.copystat(repo.wjoin(f), tmpname) backups[f] = tmpname fp = cStringIO.StringIO() @@ -521,6 +522,14 @@ for realname, tmpname in backups.iteritems(): ui.debug('restoring %r to %r\n' % (tmpname, realname)) util.copyfile(tmpname, repo.wjoin(realname)) + # Our calls to copystat() here and above are a + # hack to trick any editors that have f open that + # we haven't modified them. + # + # Also note that this racy as an editor could + # notice the file's mtime before we've finished + # writing it. + shutil.copystat(tmpname, repo.wjoin(realname)) os.unlink(tmpname) os.rmdir(backupdir) except OSError:
--- a/hgext/transplant.py Fri Dec 10 01:30:16 2010 +0100 +++ b/hgext/transplant.py Fri Dec 10 23:05:48 2010 +0100 @@ -401,7 +401,7 @@ def hasnode(repo, node): try: - return repo.changelog.rev(node) != None + return repo.changelog.rev(node) is not None except error.RevlogError: return False
--- a/i18n/da.po Fri Dec 10 01:30:16 2010 +0100 +++ b/i18n/da.po Fri Dec 10 23:05:48 2010 +0100 @@ -17,8 +17,8 @@ msgstr "" "Project-Id-Version: Mercurial\n" "Report-Msgid-Bugs-To: <mercurial-devel@selenic.com>\n" -"POT-Creation-Date: 2010-10-28 09:50+0200\n" -"PO-Revision-Date: 2010-10-28 10:01+0200\n" +"POT-Creation-Date: 2010-11-01 11:03+0100\n" +"PO-Revision-Date: 2010-11-01 11:11+0100\n" "Last-Translator: <mg@lazybytes.net>\n" "Language-Team: Danish\n" "MIME-Version: 1.0\n" @@ -3396,6 +3396,10 @@ msgstr "\"%s\" kan ikke bruges som navnet på en rettelse" #, python-format +msgid "\"%s\" already exists as a directory" +msgstr "\"%s\" eksisterer allerede som et katalog" + +#, python-format msgid "patch \"%s\" already exists" msgstr "rettelsen \"%s\" findes allerede" @@ -3403,6 +3407,10 @@ msgstr "kan ikke håndtere sammenføjninger" #, python-format +msgid "cannot write patch \"%s\": %s" +msgstr "kan ikke skrive patch \"%s\": %s" + +#, python-format msgid "error unlinking %s\n" msgstr "fejl ved sletning af %s\n" @@ -4723,10 +4731,10 @@ msgid "" " [pager]\n" -" pager = LESS='FSRX' less" +" pager = less -FRSX" msgstr "" " [pager]\n" -" pager = LESS='FSRX' less" +" pager = less -FRSX" msgid "" "If no pager is set, the pager extensions uses the environment variable\n" @@ -4734,18 +4742,6 @@ msgstr "" msgid "" -"By default, the pager is only executed if a command has output. To\n" -"force the pager to run even if a command prints nothing, set::" -msgstr "" - -msgid "" -" [pager]\n" -" force = True" -msgstr "" -" [pager]\n" -" force = True" - -msgid "" "If you notice \"BROKEN PIPE\" error messages, you can disable them by\n" "setting::" msgstr "" @@ -6225,6 +6221,12 @@ msgstr "noterer fjernelse af %s som en omdøbning til %s (%d%% lighed)\n" #, python-format +msgid "%s has not been committed yet, so no copy data will be stored for %s.\n" +msgstr "" +"%s er endnu ikke comitted, så der vil ikke blive gemt kopieringsdata for %" +"s.\n" + +#, python-format msgid "%s: not copying - file is not managed\n" msgstr "%s: kopierer ikke - filen er ikke versionsstyret\n" @@ -6264,12 +6266,6 @@ msgid "copying %s to %s\n" msgstr "kopierer %s til %s\n" -#, python-format -msgid "%s has not been committed yet, so no copy data will be stored for %s.\n" -msgstr "" -"%s er endnu ikke comitted, så der vil ikke blive gemt kopieringsdata for %" -"s.\n" - msgid "no source or destination specified" msgstr "ingen kilde eller destination angivet" @@ -9355,6 +9351,9 @@ msgid "[PATH]" msgstr "[STI]" +msgid "revlog format" +msgstr "" + msgid "REPO NAMESPACE [KEY OLD NEW]" msgstr "" @@ -12984,10 +12983,10 @@ #, python-format msgid "can't use %s here" -msgstr "" +msgstr "kan ikke bruge %s her" msgid "can't use a list in this context" -msgstr "" +msgstr "en liste kan ikke bruges i denne konteks" #, python-format msgid "not a function: %s" @@ -13004,7 +13003,7 @@ #. i18n: "id" is a keyword msgid "id requires a string" -msgstr "" +msgstr "id kræver en streng" msgid "" "``rev(number)``\n" @@ -13013,11 +13012,11 @@ #. i18n: "rev" is a keyword msgid "rev requires one argument" -msgstr "" +msgstr "rev kræver et argument" #. i18n: "rev" is a keyword msgid "rev requires a number" -msgstr "" +msgstr "rev kræver et tal" #. i18n: "rev" is a keyword msgid "rev expects a number" @@ -13298,20 +13297,23 @@ "``tag(name)``\n" " The specified tag by name, or all tagged revisions if no name is given." msgstr "" +"``tag(navn)``\n" +" Den navngivne mærkat eller alle revisioner med en mærkat hvis der\n" +" ikke angives noget navn." #. i18n: "tag" is a keyword msgid "tag takes one or no arguments" -msgstr "" +msgstr "tag tager et eller to argumenter" #. i18n: "tag" is a keyword msgid "the argument to tag must be a string" -msgstr "" +msgstr "argumentet til tag skal være en streng" msgid "can't negate that" msgstr "" msgid "not a symbol" -msgstr "" +msgstr "ikke et symbol" msgid "empty query" msgstr "tomt forespørgsel" @@ -13560,11 +13562,11 @@ msgstr "certifikatet er for %s" msgid "no commonName found in certificate" -msgstr "" +msgstr "fandt ikke noget commonName i certifikatet" #, python-format msgid "%s certificate error: %s" -msgstr "" +msgstr "%s certifikatfejl: %s" #, python-format msgid "command '%s' failed: %s" @@ -13647,7 +13649,7 @@ #, python-format msgid "no port number associated with service '%s'" -msgstr "" +msgstr "der er ikke knyttet noget portnummer til servicen '%s'" msgid "cannot verify bundle or remote repos" msgstr "kan ikke verificere bundt eller fjerndepoter" @@ -13704,7 +13706,7 @@ msgstr "duplikeret revision %d (%d)" msgid "abandoned transaction found - run hg recover\n" -msgstr "" +msgstr "fandt efterladt transaktion - kør hg recover\n" #, python-format msgid "repository uses revlog format %d\n" @@ -13738,7 +13740,7 @@ msgstr "krydstjekker filer i ændringer og manifester\n" msgid "crosschecking" -msgstr "" +msgstr "krydstjekker" #, python-format msgid "changeset refers to unknown manifest %s" @@ -13766,7 +13768,7 @@ #, python-format msgid "%s not in manifests" -msgstr "" +msgstr "%s findes ikke i manifestet" #, python-format msgid "unpacked size is %s, %s expected"
--- a/i18n/polib.py Fri Dec 10 01:30:16 2010 +0100 +++ b/i18n/polib.py Fri Dec 10 23:05:48 2010 +0100 @@ -105,7 +105,7 @@ ... finally: ... os.unlink(tmpf) """ - if kwargs.get('autodetect_encoding', True) == True: + if kwargs.get('autodetect_encoding', True): enc = detect_encoding(fpath) else: enc = kwargs.get('encoding', default_encoding) @@ -159,7 +159,7 @@ ... finally: ... os.unlink(tmpf) """ - if kwargs.get('autodetect_encoding', True) == True: + if kwargs.get('autodetect_encoding', True): enc = detect_encoding(fpath, True) else: enc = kwargs.get('encoding', default_encoding)
--- a/mercurial/archival.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/archival.py Fri Dec 10 23:05:48 2010 +0100 @@ -8,7 +8,7 @@ from i18n import _ from node import hex import cmdutil -import util +import util, encoding import cStringIO, os, stat, tarfile, time, zipfile import zlib, gzip @@ -245,7 +245,7 @@ if repo.ui.configbool("ui", "archivemeta", True): def metadata(): base = 'repo: %s\nnode: %s\nbranch: %s\n' % ( - repo[0].hex(), hex(node), ctx.branch()) + repo[0].hex(), hex(node), encoding.fromlocal(ctx.branch())) tags = ''.join('tag: %s\n' % t for t in ctx.tags() if repo.tagtype(t) == 'global')
--- a/mercurial/bdiff.c Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/bdiff.c Fri Dec 10 23:05:48 2010 +0100 @@ -57,12 +57,10 @@ int pos, len; }; +struct hunk; struct hunk { int a1, a2, b1, b2; -}; - -struct hunklist { - struct hunk *base, *head; + struct hunk *next; }; int splitlines(const char *a, int len, struct line **lr) @@ -223,8 +221,8 @@ return mk + mb; } -static void recurse(struct line *a, struct line *b, struct pos *pos, - int a1, int a2, int b1, int b2, struct hunklist *l) +static struct hunk *recurse(struct line *a, struct line *b, struct pos *pos, + int a1, int a2, int b1, int b2, struct hunk *l) { int i, j, k; @@ -232,51 +230,66 @@ /* find the longest match in this chunk */ k = longest_match(a, b, pos, a1, a2, b1, b2, &i, &j); if (!k) - return; + return l; /* and recurse on the remaining chunks on either side */ - recurse(a, b, pos, a1, i, b1, j, l); - l->head->a1 = i; - l->head->a2 = i + k; - l->head->b1 = j; - l->head->b2 = j + k; - l->head++; - /* tail-recursion didn't happen, so doing equivalent iteration */ + l = recurse(a, b, pos, a1, i, b1, j, l); + if (!l) + return NULL; + + l->next = (struct hunk *)malloc(sizeof(struct hunk)); + if (!l->next) + return NULL; + + l = l->next; + l->a1 = i; + l->a2 = i + k; + l->b1 = j; + l->b2 = j + k; + l->next = NULL; + + /* tail-recursion didn't happen, so do equivalent iteration */ a1 = i + k; b1 = j + k; } } -static struct hunklist diff(struct line *a, int an, struct line *b, int bn) +static int diff(struct line *a, int an, struct line *b, int bn, + struct hunk *base) { - struct hunklist l; struct hunk *curr; struct pos *pos; - int t; + int t, count = 0; /* allocate and fill arrays */ t = equatelines(a, an, b, bn); pos = (struct pos *)calloc(bn ? bn : 1, sizeof(struct pos)); - /* we can't have more matches than lines in the shorter file */ - l.head = l.base = (struct hunk *)malloc(sizeof(struct hunk) * - ((an<bn ? an:bn) + 1)); + + if (pos && t) { + /* generate the matching block list */ + + curr = recurse(a, b, pos, 0, an, 0, bn, base); + if (!curr) + return -1; - if (pos && l.base && t) { - /* generate the matching block list */ - recurse(a, b, pos, 0, an, 0, bn, &l); - l.head->a1 = l.head->a2 = an; - l.head->b1 = l.head->b2 = bn; - l.head++; + /* sentinel end hunk */ + curr->next = (struct hunk *)malloc(sizeof(struct hunk)); + if (!curr->next) + return -1; + curr = curr->next; + curr->a1 = curr->a2 = an; + curr->b1 = curr->b2 = bn; + curr->next = NULL; } free(pos); /* normalize the hunk list, try to push each hunk towards the end */ - for (curr = l.base; curr != l.head; curr++) { - struct hunk *next = curr + 1; + for (curr = base->next; curr; curr = curr->next) { + struct hunk *next = curr->next; int shift = 0; - if (next == l.head) + if (!next) break; if (curr->a2 == next->a1) @@ -297,16 +310,26 @@ next->a1 += shift; } - return l; + for (curr = base->next; curr; curr = curr->next) + count++; + return count; +} + +static void freehunks(struct hunk *l) +{ + struct hunk *n; + for (; l; l = n) { + n = l->next; + free(l); + } } static PyObject *blocks(PyObject *self, PyObject *args) { PyObject *sa, *sb, *rl = NULL, *m; struct line *a, *b; - struct hunklist l = {NULL, NULL}; - struct hunk *h; - int an, bn, pos = 0; + struct hunk l, *h; + int an, bn, count, pos = 0; if (!PyArg_ParseTuple(args, "SS:bdiff", &sa, &sb)) return NULL; @@ -317,12 +340,16 @@ if (!a || !b) goto nomem; - l = diff(a, an, b, bn); - rl = PyList_New(l.head - l.base); - if (!l.head || !rl) + l.next = NULL; + count = diff(a, an, b, bn, &l); + if (count < 0) goto nomem; - for (h = l.base; h != l.head; h++) { + rl = PyList_New(count); + if (!rl) + goto nomem; + + for (h = l.next; h; h = h->next) { m = Py_BuildValue("iiii", h->a1, h->a2, h->b1, h->b2); PyList_SetItem(rl, pos, m); pos++; @@ -331,7 +358,7 @@ nomem: free(a); free(b); - free(l.base); + freehunks(l.next); return rl ? rl : PyErr_NoMemory(); } @@ -340,10 +367,9 @@ char *sa, *sb; PyObject *result = NULL; struct line *al, *bl; - struct hunklist l = {NULL, NULL}; - struct hunk *h; + struct hunk l, *h; char encode[12], *rb; - int an, bn, len = 0, la, lb; + int an, bn, len = 0, la, lb, count; if (!PyArg_ParseTuple(args, "s#s#:bdiff", &sa, &la, &sb, &lb)) return NULL; @@ -353,13 +379,14 @@ if (!al || !bl) goto nomem; - l = diff(al, an, bl, bn); - if (!l.head) + l.next = NULL; + count = diff(al, an, bl, bn, &l); + if (count < 0) goto nomem; /* calculate length of output */ la = lb = 0; - for (h = l.base; h != l.head; h++) { + for (h = l.next; h; h = h->next) { if (h->a1 != la || h->b1 != lb) len += 12 + bl[h->b1].l - bl[lb].l; la = h->a2; @@ -375,7 +402,7 @@ rb = PyBytes_AsString(result); la = lb = 0; - for (h = l.base; h != l.head; h++) { + for (h = l.next; h; h = h->next) { if (h->a1 != la || h->b1 != lb) { len = bl[h->b1].l - bl[lb].l; *(uint32_t *)(encode) = htonl(al[la].l - al->l); @@ -392,7 +419,7 @@ nomem: free(al); free(bl); - free(l.base); + freehunks(l.next); return result ? result : PyErr_NoMemory(); }
--- a/mercurial/cmdutil.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/cmdutil.py Fri Dec 10 23:05:48 2010 +0100 @@ -147,6 +147,11 @@ # attempt to parse old-style ranges first to deal with # things like old-tag which contain query metacharacters try: + if isinstance(spec, int): + seen.add(spec) + l.append(spec) + continue + if revrangesep in spec: start, end = spec.split(revrangesep, 1) start = revfix(repo, start, 0) @@ -694,6 +699,8 @@ for chunk in patch.diff(repo, prev, node, opts=opts): fp.write(chunk) + fp.flush() + for seqno, rev in enumerate(revs): single(rev, seqno + 1, fp) @@ -796,7 +803,6 @@ branch = ctx.branch() # don't show the default branch name if branch != 'default': - branch = encoding.tolocal(branch) self.ui.write(_("branch: %s\n") % branch, label='log.branch') for tag in self.repo.nodetags(changenode): @@ -1352,8 +1358,7 @@ if ctx.p2(): edittext.append(_("HG: branch merge")) if ctx.branch(): - edittext.append(_("HG: branch '%s'") - % encoding.tolocal(ctx.branch())) + edittext.append(_("HG: branch '%s'") % ctx.branch()) edittext.extend([_("HG: subrepo %s") % s for s in subs]) edittext.extend([_("HG: added %s") % f for f in added]) edittext.extend([_("HG: changed %s") % f for f in modified])
--- a/mercurial/commands.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/commands.py Fri Dec 10 23:05:48 2010 +0100 @@ -126,7 +126,7 @@ lastfunc = funcmap[-1] funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1]) - ctx = repo[opts.get('rev')] + ctx = cmdutil.revsingle(repo, opts.get('rev')) m = cmdutil.match(repo, pats, opts) follow = not opts.get('no_follow') for abs in ctx.walk(m): @@ -178,7 +178,7 @@ Returns 0 on success. ''' - ctx = repo[opts.get('rev')] + ctx = cmdutil.revsingle(repo, opts.get('rev')) if not ctx: raise util.Abort(_('no working directory: please specify a revision')) node = ctx.node() @@ -243,7 +243,7 @@ opts['date'] = util.parsedate(date) cmdutil.bail_if_changed(repo) - node = repo.lookup(rev) + node = cmdutil.revsingle(repo, rev).node() op1, op2 = repo.dirstate.parents() a = repo.changelog.ancestor(op1, node) @@ -408,7 +408,8 @@ raise util.Abort(_("%s killed") % command) else: transition = "bad" - ctx = repo[rev or '.'] + ctx = cmdutil.revsingle(repo, rev) + rev = None # clear for future iterations state[transition].append(ctx.node()) ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition)) check_state(state, interactive=False) @@ -487,15 +488,14 @@ repo.dirstate.setbranch(label) ui.status(_('reset working directory to branch %s\n') % label) elif label: - utflabel = encoding.fromlocal(label) - if not opts.get('force') and utflabel in repo.branchtags(): + if not opts.get('force') and label in repo.branchtags(): if label not in [p.branch() for p in repo.parents()]: raise util.Abort(_('a branch of the same name already exists' " (use 'hg update' to switch to it)")) - repo.dirstate.setbranch(utflabel) + repo.dirstate.setbranch(label) ui.status(_('marked working directory as branch %s\n') % label) else: - ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch())) + ui.write("%s\n" % repo.dirstate.branch()) def branches(ui, repo, active=False, closed=False): """list repository named branches @@ -524,9 +524,8 @@ for isactive, node, tag in branches: if (not active) or isactive: - encodedtag = encoding.tolocal(tag) if ui.quiet: - ui.write("%s\n" % encodedtag) + ui.write("%s\n" % tag) else: hn = repo.lookup(node) if isactive: @@ -542,10 +541,10 @@ notice = _(' (inactive)') if tag == repo.dirstate.branch(): label = 'branches.current' - rev = str(node).rjust(31 - encoding.colwidth(encodedtag)) + rev = str(node).rjust(31 - encoding.colwidth(tag)) rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset') - encodedtag = ui.label(encodedtag, label) - ui.write("%s %s%s\n" % (encodedtag, rev, notice)) + tag = ui.label(tag, label) + ui.write("%s %s%s\n" % (tag, rev, notice)) def bundle(ui, repo, fname, dest=None, **opts): """create a changegroup file @@ -572,11 +571,14 @@ Returns 0 on success, 1 if no changes found. """ - revs = opts.get('rev') or None + revs = None + if 'rev' in opts: + revs = cmdutil.revrange(repo, opts['rev']) + if opts.get('all'): base = ['null'] else: - base = opts.get('base') + base = cmdutil.revrange(repo, opts.get('base')) if base: if dest: raise util.Abort(_("--base is incompatible with specifying " @@ -1026,7 +1028,7 @@ def debugrebuildstate(ui, repo, rev="tip"): """rebuild the dirstate as it would look like for the given revision""" - ctx = repo[rev] + ctx = cmdutil.revsingle(repo, rev) wlock = repo.wlock() try: repo.dirstate.rebuild(ctx.node(), ctx.manifest()) @@ -1116,7 +1118,7 @@ key, old, new = keyinfo r = target.pushkey(namespace, key, old, new) ui.status(str(r) + '\n') - return not(r) + return not r else: for k, v in target.listkeys(namespace).iteritems(): ui.write("%s\t%s\n" % (k.encode('string-escape'), @@ -1140,12 +1142,12 @@ Returns 0 on success. """ - if not rev2: - rev2 = hex(nullid) + r1 = cmdutil.revsingle(repo, rev1).node() + r2 = cmdutil.revsingle(repo, rev2, 'null').node() wlock = repo.wlock() try: - repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2)) + repo.dirstate.setparents(r1, r2) finally: wlock.release() @@ -1174,9 +1176,8 @@ ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f)) def debugsub(ui, repo, rev=None): - if rev == '': - rev = None - for k, v in sorted(repo[rev].substate.items()): + ctx = cmdutil.revsingle(repo, rev, None) + for k, v in sorted(ctx.substate.items()): ui.write('path %s\n' % k) ui.write(' source %s\n' % v[0]) ui.write(' revision %s\n' % v[1]) @@ -1435,7 +1436,7 @@ def debugrename(ui, repo, file1, *pats, **opts): """dump rename information""" - ctx = repo[opts.get('rev')] + ctx = cmdutil.revsingle(repo, opts.get('rev')) m = cmdutil.match(repo, (file1,) + pats, opts) for abs in ctx.walk(m): fctx = ctx[abs] @@ -1808,10 +1809,9 @@ Returns 0 if matching heads are found, 1 if not. """ - if opts.get('rev'): - start = repo.lookup(opts['rev']) - else: - start = None + start = None + if 'rev' in opts: + start = cmdutil.revsingle(repo, opts['rev'], None).node() if opts.get('topo'): heads = [repo[h] for h in repo.heads(start)] @@ -1828,8 +1828,7 @@ heads += [repo[h] for h in ls if rev(h) in descendants] if branchrevs: - decode, encode = encoding.fromlocal, encoding.tolocal - branches = set(repo[decode(br)].branch() for br in branchrevs) + branches = set(repo[br].branch() for br in branchrevs) heads = [h for h in heads if h.branch() in branches] if not opts.get('closed'): @@ -1842,7 +1841,7 @@ if branchrevs: haveheads = set(h.branch() for h in heads) if branches - haveheads: - headless = ', '.join(encode(b) for b in branches - haveheads) + headless = ', '.join(b for b in branches - haveheads) msg = _('no open branch heads found on branches %s') if opts.get('rev'): msg += _(' (started at %s)' % opts['rev']) @@ -2200,14 +2199,14 @@ output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]), (changed) and "+" or "")) else: - ctx = repo[rev] + ctx = cmdutil.revsingle(repo, rev) if default or id: output = [hexfunc(ctx.node())] if num: output.append(str(ctx.rev())) if repo.local() and default and not ui.quiet: - b = encoding.tolocal(ctx.branch()) + b = ctx.branch() if b != 'default': output.append("(%s)" % b) @@ -2217,7 +2216,7 @@ output.append(t) if branch: - output.append(encoding.tolocal(ctx.branch())) + output.append(ctx.branch()) if tags: output.extend(ctx.tags()) @@ -2279,6 +2278,7 @@ d = opts["base"] strip = opts["strip"] wlock = lock = None + msgs = [] def tryone(ui, hunk): tmpname, message, user, date, branch, nodeid, p1, p2 = \ @@ -2329,7 +2329,10 @@ finally: files = cmdutil.updatedir(ui, repo, files, similarity=sim / 100.0) - if not opts.get('no_commit'): + if opts.get('no_commit'): + if message: + msgs.append(message) + else: if opts.get('exact'): m = None else: @@ -2378,6 +2381,8 @@ if not haspatch: raise util.Abort(_('no diffs found')) + if msgs: + repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs)) finally: release(lock, wlock) @@ -2437,7 +2442,7 @@ Returns 0 if a match is found, 1 otherwise. """ end = opts.get('print0') and '\0' or '\n' - rev = opts.get('rev') or None + rev = cmdutil.revsingle(repo, opts.get('rev'), None).node() ret = 1 m = cmdutil.match(repo, pats, opts, default='relglob') @@ -2572,7 +2577,7 @@ node = rev decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '} - ctx = repo[node] + ctx = cmdutil.revsingle(repo, node) for f in ctx: if ui.debugflag: ui.write("%40s " % hex(ctx.manifest()[f])) @@ -2615,7 +2620,7 @@ node = opts.get('rev') if not node: - branch = repo.changectx(None).branch() + branch = repo[None].branch() bheads = repo.branchheads(branch) if len(bheads) > 2: raise util.Abort(_( @@ -2641,6 +2646,8 @@ raise util.Abort(_('working dir not at a head rev - ' 'use "hg update" or merge with an explicit rev')) node = parent == bheads[0] and bheads[-1] or bheads[0] + else: + node = cmdutil.revsingle(repo, node).node() if opts.get('preview'): # find nodes that are ancestors of p2 but not of p1 @@ -2686,11 +2693,8 @@ Returns 0 on success. """ - rev = opts.get('rev') - if rev: - ctx = repo[rev] - else: - ctx = repo[None] + + ctx = cmdutil.revsingle(repo, opts.get('rev'), None) if file_: m = cmdutil.match(repo, (file_,), opts) @@ -3098,15 +3102,16 @@ raise util.Abort(_("you can't specify a revision and a date")) opts["rev"] = cmdutil.finddate(ui, repo, opts["date"]) + parent, p2 = repo.dirstate.parents() + if not opts.get('rev') and p2 != nullid: + raise util.Abort(_('uncommitted merge - ' + 'use "hg update", see "hg help revert"')) + if not pats and not opts.get('all'): raise util.Abort(_('no files or directories specified; ' 'use --all to revert the whole repo')) - parent, p2 = repo.dirstate.parents() - if not opts.get('rev') and p2 != nullid: - raise util.Abort(_('uncommitted merge - please provide a ' - 'specific revision')) - ctx = repo[opts.get('rev')] + ctx = cmdutil.revsingle(repo, opts.get('rev')) node = ctx.node() mf = ctx.manifest() if node == parent: @@ -3715,7 +3720,7 @@ if not rev_ and repo.dirstate.parents()[1] != nullid: raise util.Abort(_('uncommitted merge - please provide a ' 'specific revision')) - r = repo[rev_].node() + r = cmdutil.revsingle(repo, rev_).node() if not message: # we don't translate commit messages
--- a/mercurial/config.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/config.py Fri Dec 10 23:05:48 2010 +0100 @@ -130,7 +130,7 @@ name = m.group(1) if sections and section not in sections: continue - if self.get(section, name) != None: + if self.get(section, name) is not None: del self._data[section][name] continue
--- a/mercurial/context.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/context.py Fri Dec 10 23:05:48 2010 +0100 @@ -7,7 +7,7 @@ from node import nullid, nullrev, short, hex from i18n import _ -import ancestor, bdiff, error, util, subrepo, patch +import ancestor, bdiff, error, util, subrepo, patch, encoding import os, errno, stat propertycache = util.propertycache @@ -109,7 +109,7 @@ def description(self): return self._changeset[4] def branch(self): - return self._changeset[5].get("branch") + return encoding.tolocal(self._changeset[5].get("branch")) def extra(self): return self._changeset[5] def tags(self): @@ -179,7 +179,7 @@ """ # deal with workingctxs n2 = c2._node - if n2 == None: + if n2 is None: n2 = c2._parents[0]._node n = self._repo.changelog.ancestor(self._node, n2) return changectx(self._repo, n) @@ -591,9 +591,8 @@ if extra: self._extra = extra.copy() if 'branch' not in self._extra: - branch = self._repo.dirstate.branch() try: - branch = branch.decode('UTF-8').encode('UTF-8') + branch = encoding.fromlocal(self._repo.dirstate.branch()) except UnicodeDecodeError: raise util.Abort(_('branch name not in UTF-8!')) self._extra['branch'] = branch @@ -603,6 +602,9 @@ def __str__(self): return str(self._parents[0]) + "+" + def __repr__(self): + return "<workingctx %s>" % str(self) + def __nonzero__(self): return True @@ -712,7 +714,7 @@ assert self._clean is not None # must call status first return self._clean def branch(self): - return self._extra['branch'] + return encoding.tolocal(self._extra['branch']) def extra(self): return self._extra @@ -902,6 +904,9 @@ def __str__(self): return "%s@%s" % (self.path(), self._changectx) + def __repr__(self): + return "<workingfilectx %s>" % str(self) + def data(self): return self._repo.wread(self._path) def renamed(self): @@ -1042,7 +1047,7 @@ def clean(self): return self._status[6] def branch(self): - return self._extra['branch'] + return encoding.tolocal(self._extra['branch']) def extra(self): return self._extra def flags(self, f):
--- a/mercurial/demandimport.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/demandimport.py Fri Dec 10 23:05:48 2010 +0100 @@ -78,10 +78,10 @@ self._load() setattr(self._module, attr, val) -def _demandimport(name, globals=None, locals=None, fromlist=None, level=None): +def _demandimport(name, globals=None, locals=None, fromlist=None, level=-1): if not locals or name in ignore or fromlist == ('*',): # these cases we can't really delay - if level is None: + if level == -1: return _origimport(name, globals, locals, fromlist) else: return _origimport(name, globals, locals, fromlist, level) @@ -91,7 +91,10 @@ base, rest = name.split('.', 1) # email.__init__ loading email.mime if globals and globals.get('__name__', None) == base: - return _origimport(name, globals, locals, fromlist) + if level != -1: + return _origimport(name, globals, locals, fromlist, level) + else: + return _origimport(name, globals, locals, fromlist) # if a is already demand-loaded, add b to its submodule list if base in locals: if isinstance(locals[base], _demandmod): @@ -99,7 +102,7 @@ return locals[base] return _demandmod(name, globals, locals) else: - if level is not None: + if level != -1: # from . import b,c,d or from .a import b,c,d return _origimport(name, globals, locals, fromlist, level) # from a import b,c,d @@ -111,7 +114,7 @@ mod = getattr(mod, comp) for x in fromlist: # set requested submodules for demand load - if not(hasattr(mod, x)): + if not hasattr(mod, x): setattr(mod, x, _demandmod(x, mod.__dict__, locals)) return mod
--- a/mercurial/dirstate.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/dirstate.py Fri Dec 10 23:05:48 2010 +0100 @@ -7,7 +7,7 @@ from node import nullid from i18n import _ -import util, ignore, osutil, parsers +import util, ignore, osutil, parsers, encoding import struct, os, stat, errno import cStringIO @@ -36,7 +36,7 @@ class dirstate(object): - def __init__(self, opener, ui, root): + def __init__(self, opener, ui, root, validate): '''Create a new dirstate object. opener is an open()-like callable that can be used to open the @@ -44,6 +44,7 @@ the dirstate. ''' self._opener = opener + self._validate = validate self._root = root self._rootdir = os.path.join(root, '') self._dirty = False @@ -197,10 +198,10 @@ yield x def parents(self): - return self._pl + return [self._validate(p) for p in self._pl] def branch(self): - return self._branch + return encoding.tolocal(self._branch) def setparents(self, p1, p2=nullid): self._dirty = self._dirtypl = True @@ -209,8 +210,8 @@ def setbranch(self, branch): if branch in ['tip', '.', 'null']: raise util.Abort(_('the name \'%s\' is reserved') % branch) - self._branch = branch - self._opener("branch", "w").write(branch + '\n') + self._branch = encoding.fromlocal(branch) + self._opener("branch", "w").write(self._branch + '\n') def _read(self): self._map = {}
--- a/mercurial/discovery.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/discovery.py Fri Dec 10 23:05:48 2010 +0100 @@ -220,8 +220,6 @@ # - a local outgoing head descended from update # - a remote head that's known locally and not # ancestral to an outgoing head - # - # New named branches cannot be created without --force. # 1. Create set of branches involved in the push. branches = set(repo[n].branch() for n in outg) @@ -280,20 +278,30 @@ # 5. Check for new heads. # If there are more heads after the push than before, a suitable - # warning, depending on unsynced status, is displayed. + # error message, depending on unsynced status, is displayed. + error = None for branch in branches: - if len(newmap[branch]) > len(oldmap[branch]): + newhs = set(newmap[branch]) + oldhs = set(oldmap[branch]) + if len(newhs) > len(oldhs): + if error is None: + if branch: + error = _("push creates new remote heads " + "on branch '%s'!") % branch + else: + error = _("push creates new remote heads!") + if branch in unsynced: + hint = _("you should pull and merge or " + "use push -f to force") + else: + hint = _("did you forget to merge? " + "use push -f to force") if branch: - msg = _("push creates new remote heads " - "on branch '%s'!") % branch - else: - msg = _("push creates new remote heads!") - - if branch in unsynced: - hint = _("you should pull and merge or use push -f to force") - else: - hint = _("did you forget to merge? use push -f to force") - raise util.Abort(msg, hint=hint) + repo.ui.debug("new remote heads on branch '%s'\n" % branch) + for h in (newhs - oldhs): + repo.ui.debug("new remote head %s\n" % short(h)) + if error: + raise util.Abort(error, hint=hint) # 6. Check for unsynced changes on involved branches. if unsynced:
--- a/mercurial/encoding.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/encoding.py Fri Dec 10 23:05:48 2010 +0100 @@ -48,6 +48,16 @@ encodingmode = os.environ.get("HGENCODINGMODE", "strict") fallbackencoding = 'ISO-8859-1' +class localstr(str): + '''This class allows strings that are unmodified to be + round-tripped to the local encoding and back''' + def __new__(cls, u, l): + s = str.__new__(cls, l) + s._utf8 = u + return s + def __hash__(self): + return hash(self._utf8) # avoid collisions in local string space + def tolocal(s): """ Convert a string from internal UTF-8 to local encoding @@ -57,17 +67,45 @@ other character sets. We attempt to decode everything strictly using UTF-8, then Latin-1, and failing that, we use UTF-8 and replace unknown characters. + + The localstr class is used to cache the known UTF-8 encoding of + strings next to their local representation to allow lossless + round-trip conversion back to UTF-8. + + >>> u = 'foo: \\xc3\\xa4' # utf-8 + >>> l = tolocal(u) + >>> l + 'foo: ?' + >>> fromlocal(l) + 'foo: \\xc3\\xa4' + >>> u2 = 'foo: \\xc3\\xa1' + >>> d = { l: 1, tolocal(u2): 2 } + >>> d # no collision + {'foo: ?': 1, 'foo: ?': 2} + >>> 'foo: ?' in d + False + >>> l1 = 'foo: \\xe4' # historical latin1 fallback + >>> l = tolocal(l1) + >>> l + 'foo: ?' + >>> fromlocal(l) # magically in utf-8 + 'foo: \\xc3\\xa4' """ + for e in ('UTF-8', fallbackencoding): try: u = s.decode(e) # attempt strict decoding - return u.encode(encoding, "replace") + if e == 'UTF-8': + return localstr(s, u.encode(encoding, "replace")) + else: + return localstr(u.encode('UTF-8'), + u.encode(encoding, "replace")) except LookupError, k: raise error.Abort("%s, please check your locale settings" % k) except UnicodeDecodeError: pass u = s.decode("utf-8", "replace") # last ditch - return u.encode(encoding, "replace") + return u.encode(encoding, "replace") # can't round-trip def fromlocal(s): """ @@ -79,6 +117,11 @@ 'replace', which replaces unknown characters with a special Unicode character, and 'ignore', which drops the character. """ + + # can we do a lossless round-trip? + if isinstance(s, localstr): + return s._utf8 + try: return s.decode(encoding, encodingmode).encode("utf-8") except UnicodeDecodeError, inst:
--- a/mercurial/hg.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/hg.py Fri Dec 10 23:05:48 2010 +0100 @@ -32,24 +32,22 @@ return revs, revs[0] branchmap = repo.branchmap() - def primary(butf8): - if butf8 == '.': + def primary(branch): + if branch == '.': if not lrepo or not lrepo.local(): raise util.Abort(_("dirstate branch not accessible")) - butf8 = lrepo.dirstate.branch() - if butf8 in branchmap: - revs.extend(node.hex(r) for r in reversed(branchmap[butf8])) + branch = lrepo.dirstate.branch() + if branch in branchmap: + revs.extend(node.hex(r) for r in reversed(branchmap[branch])) return True else: return False for branch in branches: - butf8 = encoding.fromlocal(branch) - if not primary(butf8): + if not primary(branch): raise error.RepoLookupError(_("unknown branch '%s'") % branch) if hashbranch: - butf8 = encoding.fromlocal(hashbranch) - if not primary(butf8): + if not primary(hashbranch): revs.append(hashbranch) return revs, revs[0] @@ -365,8 +363,7 @@ except error.RepoLookupError: continue bn = dest_repo[uprev].branch() - dest_repo.ui.status(_("updating to branch %s\n") - % encoding.tolocal(bn)) + dest_repo.ui.status(_("updating to branch %s\n") % bn) _update(dest_repo, uprev) return src_repo, dest_repo
--- a/mercurial/localrepo.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/localrepo.py Fri Dec 10 23:05:48 2010 +0100 @@ -105,7 +105,7 @@ self._tags = None self._tagtypes = None - self._branchcache = None # in UTF-8 + self._branchcache = None self._branchcachetip = None self.nodetagscache = None self.filterpats = {} @@ -178,7 +178,19 @@ @propertycache def dirstate(self): - return dirstate.dirstate(self.opener, self.ui, self.root) + warned = [0] + def validate(node): + try: + r = self.changelog.rev(node) + return node + except error.LookupError: + if not warned[0]: + warned[0] = True + self.ui.warn(_("warning: ignoring unknown" + " working parent %s!\n") % short(node)) + return nullid + + return dirstate.dirstate(self.opener, self.ui, self.root, validate) def __getitem__(self, changeid): if changeid is None: @@ -423,7 +435,6 @@ bt[bn] = tip return bt - def _readbranchcache(self): partial = {} try: @@ -443,7 +454,8 @@ if not l: continue node, label = l.split(" ", 1) - partial.setdefault(label.strip(), []).append(bin(node)) + label = encoding.tolocal(label.strip()) + partial.setdefault(label, []).append(bin(node)) except KeyboardInterrupt: raise except Exception, inst: @@ -458,7 +470,7 @@ f.write("%s %s\n" % (hex(tip), tiprev)) for label, nodes in branches.iteritems(): for node in nodes: - f.write("%s %s\n" % (hex(node), label)) + f.write("%s %s\n" % (hex(node), encoding.fromlocal(label))) f.rename() except (IOError, OSError): pass @@ -647,7 +659,8 @@ except IOError: ds = "" self.opener("journal.dirstate", "w").write(ds) - self.opener("journal.branch", "w").write(self.dirstate.branch()) + self.opener("journal.branch", "w").write( + encoding.fromlocal(self.dirstate.branch())) self.opener("journal.desc", "w").write("%d\n%s\n" % (len(self), desc)) renames = [(self.sjoin("journal"), self.sjoin("undo")), @@ -705,7 +718,7 @@ except IOError: self.ui.warn(_("Named branch could not be reset, " "current branch still is: %s\n") - % encoding.tolocal(self.dirstate.branch())) + % self.dirstate.branch()) self.invalidate() self.dirstate.invalidate() self.destroyed() @@ -1207,8 +1220,7 @@ def heads(self, start=None): heads = self.changelog.heads(start) # sort the output in rev descending order - heads = [(-self.changelog.rev(h), h) for h in heads] - return [n for (r, n) in sorted(heads)] + return sorted(heads, key=self.changelog.rev, reverse=True) def branchheads(self, branch=None, start=None, closed=False): '''return a (possibly filtered) list of heads for the given branch
--- a/mercurial/manifest.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/manifest.py Fri Dec 10 23:05:48 2010 +0100 @@ -171,19 +171,19 @@ raise AssertionError( _("failed to remove %s from manifest") % f) l = "" - if dstart != None and dstart <= start and dend >= start: + if dstart is not None and dstart <= start and dend >= start: if dend < end: dend = end if l: dline.append(l) else: - if dstart != None: + if dstart is not None: delta.append([dstart, dend, "".join(dline)]) dstart = start dend = end dline = [l] - if dstart != None: + if dstart is not None: delta.append([dstart, dend, "".join(dline)]) # apply the delta to the addlist, and get a delta for addrevision cachedelta = (self.rev(p1), addlistdelta(addlist, delta))
--- a/mercurial/minirst.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/minirst.py Fri Dec 10 23:05:48 2010 +0100 @@ -14,27 +14,8 @@ are just indented blocks that look like they are nested. This relies on the user to keep the right indentation for the blocks. -It only supports a small subset of reStructuredText: - -- sections - -- paragraphs - -- literal blocks - -- definition lists - -- specific admonitions - -- bullet lists (items must start with '-') - -- enumerated lists (no autonumbering) - -- field lists (colons cannot be escaped) - -- option lists (supports only long options without arguments) - -- inline literals (no other inline markup is not recognized) +Remember to update http://mercurial.selenic.com/wiki/HelpStyleGuide +when adding support for new constructs. """ import re, sys @@ -118,7 +99,8 @@ return blocks _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ') -_optionre = re.compile(r'^(--[a-z-]+)((?:[ =][a-zA-Z][\w-]*)? +)(.*)$') +_optionre = re.compile(r'^(-([a-zA-Z0-9]), )?(--[a-z0-9-]+)' + r'((.*) +)(.*)$') _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)') _definitionre = re.compile(r'[^ ]') @@ -192,6 +174,42 @@ return blocks +def updateoptionlists(blocks): + i = 0 + while i < len(blocks): + if blocks[i]['type'] != 'option': + i += 1 + continue + + optstrwidth = 0 + j = i + while j < len(blocks) and blocks[j]['type'] == 'option': + m = _optionre.match(blocks[j]['lines'][0]) + + shortoption = m.group(2) + group3 = m.group(3) + longoption = group3[2:].strip() + desc = m.group(6).strip() + longoptionarg = m.group(5).strip() + blocks[j]['lines'][0] = desc + + noshortop = '' + if not shortoption: + noshortop = ' ' + + opt = "%s%s" % (shortoption and "-%s " % shortoption or '', + ("%s--%s %s") % (noshortop, longoption, + longoptionarg)) + opt = opt.rstrip() + blocks[j]['optstr'] = opt + optstrwidth = max(optstrwidth, encoding.colwidth(opt)) + j += 1 + + for block in blocks[i:j]: + block['optstrwidth'] = optstrwidth + i = j + 1 + return blocks + def prunecontainers(blocks, keep): """Prune unwanted containers. @@ -297,8 +315,11 @@ i = 0 while i < len(blocks): b = blocks[i] - if b['type'] == 'paragraph' and b['lines'][0].startswith('.. '): + if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or + b['lines'] == ['..']): del blocks[i] + if i < len(blocks) and blocks[i]['type'] == 'margin': + del blocks[i] else: i += 1 return blocks @@ -338,6 +359,17 @@ 'tip': _('Tip:'), 'warning': _('Warning!')} +def formatoption(block, width): + desc = ' '.join(map(str.strip, block['lines'])) + colwidth = encoding.colwidth(block['optstr']) + usablewidth = width - 1 + hanging = block['optstrwidth'] + initindent = '%s%s ' % (block['optstr'], ' ' * ((hanging - colwidth))) + hangindent = ' ' * (encoding.colwidth(initindent) + 1) + return ' %s' % (util.wrap(desc, usablewidth, + initindent=initindent, + hangindent=hangindent)) + def formatblock(block, width): """Format a block according to width.""" if width <= 0: @@ -394,9 +426,7 @@ key = key.ljust(_fieldwidth) block['lines'][0] = key + block['lines'][0] elif block['type'] == 'option': - m = _optionre.match(block['lines'][0]) - option, arg, rest = m.groups() - subindent = indent + (len(option) + len(arg)) * ' ' + return formatoption(block, width) text = ' '.join(map(str.strip, block['lines'])) return util.wrap(text, width=width, @@ -416,8 +446,9 @@ blocks = hgrole(blocks) blocks = splitparagraphs(blocks) blocks = updatefieldlists(blocks) + blocks = updateoptionlists(blocks) + blocks = addmargins(blocks) blocks = prunecomments(blocks) - blocks = addmargins(blocks) blocks = findadmonitions(blocks) text = '\n'.join(formatblock(b, width) for b in blocks) if keep is None: @@ -443,8 +474,9 @@ blocks = debug(inlineliterals, blocks) blocks = debug(splitparagraphs, blocks) blocks = debug(updatefieldlists, blocks) + blocks = debug(updateoptionlists, blocks) blocks = debug(findsections, blocks) + blocks = debug(addmargins, blocks) blocks = debug(prunecomments, blocks) - blocks = debug(addmargins, blocks) blocks = debug(findadmonitions, blocks) print '\n'.join(formatblock(b, 30) for b in blocks)
--- a/mercurial/patch.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/patch.py Fri Dec 10 23:05:48 2010 +0100 @@ -976,7 +976,7 @@ fp.seek(pos) return gitpatches -def iterhunks(ui, fp, sourcefile=None): +def iterhunks(ui, fp): """Read a patch and yield the following events: - ("file", afile, bfile, firsthunk): select a new target file. - ("hunk", hunk): a new hunk is ready to be applied, follows a @@ -997,10 +997,6 @@ BFILE = 1 context = None lr = linereader(fp) - # gitworkdone is True if a git operation (copy, rename, ...) was - # performed already for the current file. Useful when the file - # section may have no hunk. - gitworkdone = False while True: newfile = newgitfile = False @@ -1012,7 +1008,7 @@ current_hunk.fix_newline() yield 'hunk', current_hunk current_hunk = None - if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or + if (state == BFILE and ((not context and x[0] == '@') or ((context is not False) and x.startswith('***************')))): if context is None and x.startswith('***************'): context = True @@ -1034,7 +1030,6 @@ elif x.startswith('diff --git'): # check for git diff, scanning the whole patch file if needed m = gitre.match(x) - gitworkdone = False if m: afile, bfile = m.group(1, 2) if not git: @@ -1049,7 +1044,6 @@ if gp and (gp.op in ('COPY', 'DELETE', 'RENAME', 'ADD') or gp.mode): afile = bfile - gitworkdone = True newgitfile = True elif x.startswith('---'): # check for a unified diff @@ -1077,9 +1071,6 @@ afile = parsefilename(x) bfile = parsefilename(l2) - if newfile: - gitworkdone = False - if newgitfile or newfile: emitfile = True state = BFILE @@ -1091,7 +1082,7 @@ raise PatchError(_("malformed patch %s %s") % (afile, current_hunk.desc)) -def applydiff(ui, fp, changed, strip=1, sourcefile=None, eolmode='strict'): +def applydiff(ui, fp, changed, strip=1, eolmode='strict'): """Reads a patch from fp and tries to apply it. The dict 'changed' is filled in with all of the filenames changed @@ -1105,13 +1096,10 @@ Callers probably want to call 'cmdutil.updatedir' after this to apply certain categories of changes not done by this function. """ - return _applydiff( - ui, fp, patchfile, copyfile, - changed, strip=strip, sourcefile=sourcefile, eolmode=eolmode) + return _applydiff(ui, fp, patchfile, copyfile, changed, strip=strip, + eolmode=eolmode) - -def _applydiff(ui, fp, patcher, copyfn, changed, strip=1, - sourcefile=None, eolmode='strict'): +def _applydiff(ui, fp, patcher, copyfn, changed, strip=1, eolmode='strict'): rejects = 0 err = 0 current_file = None @@ -1126,7 +1114,7 @@ current_file.write_rej() return len(current_file.rej) - for state, values in iterhunks(ui, fp, sourcefile): + for state, values in iterhunks(ui, fp): if state == 'hunk': if not current_file: continue @@ -1139,14 +1127,10 @@ rejects += closefile() afile, bfile, first_hunk = values try: - if sourcefile: - current_file = patcher(ui, sourcefile, opener, - eolmode=eolmode) - else: - current_file, missing = selectfile(afile, bfile, - first_hunk, strip) - current_file = patcher(ui, current_file, opener, - missing=missing, eolmode=eolmode) + current_file, missing = selectfile(afile, bfile, + first_hunk, strip) + current_file = patcher(ui, current_file, opener, + missing=missing, eolmode=eolmode) except PatchError, err: ui.warn(str(err) + '\n') current_file = None
--- a/mercurial/revlog.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/revlog.py Fri Dec 10 23:05:48 2010 +0100 @@ -212,7 +212,7 @@ return None self.mapfind_count += 1 last = self.l - 1 - while self.index[last] != None: + while self.index[last] is not None: if last == 0: self.all = 1 self.allmap = 1
--- a/mercurial/revset.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/revset.py Fri Dec 10 23:05:48 2010 +0100 @@ -202,9 +202,13 @@ return [r for r in subset if r == l] def p1(repo, subset, x): - """``p1(set)`` - First parent of changesets in set. + """``p1([set])`` + First parent of changesets in set, or the working directory. """ + if x is None: + p = repo[x].parents()[0].rev() + return [r for r in subset if r == p] + ps = set() cl = repo.changelog for r in getset(repo, range(len(repo)), x): @@ -212,9 +216,17 @@ return [r for r in subset if r in ps] def p2(repo, subset, x): - """``p2(set)`` - Second parent of changesets in set. + """``p2([set])`` + Second parent of changesets in set, or the working directory. """ + if x is None: + ps = repo[x].parents() + try: + p = ps[1].rev() + return [r for r in subset if r == p] + except IndexError: + return [] + ps = set() cl = repo.changelog for r in getset(repo, range(len(repo)), x): @@ -222,9 +234,13 @@ return [r for r in subset if r in ps] def parents(repo, subset, x): - """``parents(set)`` - The set of all parents for all changesets in set. + """``parents([set])`` + The set of all parents for all changesets in set, or the working directory. """ + if x is None: + ps = tuple(p.rev() for p in repo[x].parents()) + return [r for r in subset if r in ps] + ps = set() cl = repo.changelog for r in getset(repo, range(len(repo)), x): @@ -699,7 +715,7 @@ } def optimize(x, small): - if x == None: + if x is None: return 0, x smallbonus = 1
--- a/mercurial/sshrepo.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/sshrepo.py Fri Dec 10 23:05:48 2010 +0100 @@ -91,10 +91,11 @@ size = util.fstat(self.pipee).st_size if size == 0: break - l = self.pipee.readline() - if not l: + s = self.pipee.read(size) + if not s: break - self.ui.status(_("remote: "), l) + for l in s.splitlines(): + self.ui.status(_("remote: "), l, '\n') def _abort(self, exception): self.cleanup()
--- a/mercurial/subrepo.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/subrepo.py Fri Dec 10 23:05:48 2010 +0100 @@ -6,7 +6,7 @@ # GNU General Public License version 2 or any later version. import errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath -import stat, subprocess +import stat, subprocess, tarfile from i18n import _ import config, util, node, error, cmdutil hg = None @@ -606,7 +606,282 @@ return self._svncommand(['cat'], name) +class gitsubrepo(object): + def __init__(self, ctx, path, state): + # TODO add git version check. + self._state = state + self._ctx = ctx + self._relpath = path + self._path = ctx._repo.wjoin(path) + self._ui = ctx._repo.ui + + def _gitcommand(self, commands, env=None, stream=False): + return self._gitdir(commands, env=env, stream=stream)[0] + + def _gitdir(self, commands, env=None, stream=False): + commands = ['--no-pager'] + commands + return self._gitnodir(commands, env=env, stream=stream, cwd=self._path) + + def _gitnodir(self, commands, env=None, stream=False, cwd=None): + """Calls the git command + + The methods tries to call the git command. versions previor to 1.6.0 + are not supported and very probably fail. + """ + cmd = ['git'] + commands + cmd = [util.shellquote(arg) for arg in cmd] + cmd = util.quotecommand(' '.join(cmd)) + + # print git's stderr, which is mostly progress and useful info + p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=cwd, env=env, + close_fds=util.closefds, + stdout=subprocess.PIPE) + if stream: + return p.stdout, None + + retdata = p.stdout.read().strip() + # wait for the child to exit to avoid race condition. + p.wait() + + if p.returncode != 0: + # there are certain error codes that are ok + command = None + for arg in commands: + if not arg.startswith('-'): + command = arg + break + if command == 'cat-file': + return retdata, p.returncode + if command in ('commit', 'status') and p.returncode == 1: + return retdata, p.returncode + # for all others, abort + raise util.Abort('git %s error %d' % (command, p.returncode)) + + return retdata, p.returncode + + def _gitstate(self): + return self._gitcommand(['rev-parse', 'HEAD']) + + def _githavelocally(self, revision): + out, code = self._gitdir(['cat-file', '-e', revision]) + return code == 0 + + def _gitisancestor(self, r1, r2): + base = self._gitcommand(['merge-base', r1, r2]) + return base == r1 + + def _gitbranchmap(self): + '''returns 3 things: + the current branch, + a map from git branch to revision + a map from revision to branches''' + branch2rev = {} + rev2branch = {} + current = None + out = self._gitcommand(['branch', '-a', '--no-color', + '--verbose', '--no-abbrev']) + for line in out.split('\n'): + if line[2:].startswith('(no branch)'): + continue + branch, revision = line[2:].split()[:2] + if revision == '->' or branch.endswith('/HEAD'): + continue # ignore remote/HEAD redirects + if '/' in branch and not branch.startswith('remotes/'): + # old git compatability + branch = 'remotes/' + branch + if line[0] == '*': + current = branch + branch2rev[branch] = revision + rev2branch.setdefault(revision, []).append(branch) + return current, branch2rev, rev2branch + + def _gittracking(self, branches): + 'return map of remote branch to local tracking branch' + # assumes no more than one local tracking branch for each remote + tracking = {} + for b in branches: + if b.startswith('remotes/'): + continue + remote = self._gitcommand(['config', 'branch.%s.remote' % b]) + if remote: + ref = self._gitcommand(['config', 'branch.%s.merge' % b]) + tracking['remotes/%s/%s' % (remote, ref.split('/')[-1])] = b + return tracking + + def _fetch(self, source, revision): + if not os.path.exists('%s/.git' % self._path): + self._ui.status(_('cloning subrepo %s\n') % self._relpath) + self._gitnodir(['clone', source, self._path]) + if self._githavelocally(revision): + return + self._ui.status(_('pulling subrepo %s\n') % self._relpath) + # first try from origin + self._gitcommand(['fetch']) + if self._githavelocally(revision): + return + # then try from known subrepo source + self._gitcommand(['fetch', source]) + if not self._githavelocally(revision): + raise util.Abort(_("revision %s does not exist in subrepo %s\n") % + (revision, self._path)) + + def dirty(self): + if self._state[1] != self._gitstate(): # version checked out changed? + return True + # check for staged changes or modified files; ignore untracked files + status = self._gitcommand(['status']) + return ('\n# Changed but not updated:' in status or + '\n# Changes to be committed:' in status) + + def get(self, state): + source, revision, kind = state + self._fetch(source, revision) + # if the repo was set to be bare, unbare it + if self._gitcommand(['config', '--bool', 'core.bare']) == 'true': + self._gitcommand(['config', 'core.bare', 'false']) + if self._gitstate() == revision: + self._gitcommand(['reset', '--hard', 'HEAD']) + return + elif self._gitstate() == revision: + return + current, branch2rev, rev2branch = self._gitbranchmap() + + def rawcheckout(): + # no branch to checkout, check it out with no branch + self._ui.warn(_('checking out detached HEAD in subrepo %s\n') % + self._relpath) + self._ui.warn(_('check out a git branch if you intend ' + 'to make changes\n')) + self._gitcommand(['checkout', '-q', revision]) + + if revision not in rev2branch: + rawcheckout() + return + branches = rev2branch[revision] + firstlocalbranch = None + for b in branches: + if b == 'master': + # master trumps all other branches + self._gitcommand(['checkout', 'master']) + return + if not firstlocalbranch and not b.startswith('remotes/'): + firstlocalbranch = b + if firstlocalbranch: + self._gitcommand(['checkout', firstlocalbranch]) + return + + tracking = self._gittracking(branch2rev.keys()) + # choose a remote branch already tracked if possible + remote = branches[0] + if remote not in tracking: + for b in branches: + if b in tracking: + remote = b + break + + if remote not in tracking: + # create a new local tracking branch + local = remote.split('/')[-1] + self._gitcommand(['checkout', '-b', local, remote]) + elif self._gitisancestor(branch2rev[tracking[remote]], remote): + # When updating to a tracked remote branch, + # if the local tracking branch is downstream of it, + # a normal `git pull` would have performed a "fast-forward merge" + # which is equivalent to updating the local branch to the remote. + # Since we are only looking at branching at update, we need to + # detect this situation and perform this action lazily. + if tracking[remote] != current: + self._gitcommand(['checkout', tracking[remote]]) + self._gitcommand(['merge', '--ff', remote]) + else: + # a real merge would be required, just checkout the revision + rawcheckout() + + def commit(self, text, user, date): + cmd = ['commit', '-a', '-m', text] + env = os.environ.copy() + if user: + cmd += ['--author', user] + if date: + # git's date parser silently ignores when seconds < 1e9 + # convert to ISO8601 + env['GIT_AUTHOR_DATE'] = util.datestr(date, + '%Y-%m-%dT%H:%M:%S %1%2') + self._gitcommand(cmd, env=env) + # make sure commit works otherwise HEAD might not exist under certain + # circumstances + return self._gitstate() + + def merge(self, state): + source, revision, kind = state + self._fetch(source, revision) + base = self._gitcommand(['merge-base', revision, self._state[1]]) + if base == revision: + self.get(state) # fast forward merge + elif base != self._state[1]: + self._gitcommand(['merge', '--no-commit', revision]) + + def push(self, force): + # if a branch in origin contains the revision, nothing to do + current, branch2rev, rev2branch = self._gitbranchmap() + for b, revision in branch2rev.iteritems(): + if b.startswith('remotes/origin'): + if self._gitisancestor(self._state[1], revision): + return True + # otherwise, try to push the currently checked out branch + cmd = ['push'] + if force: + cmd.append('--force') + if current: + # determine if the current branch is even useful + if not self._gitisancestor(self._state[1], current): + self._ui.warn(_('unrelated git branch checked out ' + 'in subrepo %s\n') % self._relpath) + return False + self._ui.status(_('pushing branch %s of subrepo %s\n') % + (current, self._relpath)) + self._gitcommand(cmd + ['origin', current]) + return True + else: + self._ui.warn(_('no branch checked out in subrepo %s\n' + 'cannot push revision %s') % + (self._relpath, self._state[1])) + return False + + def remove(self): + if self.dirty(): + self._ui.warn(_('not removing repo %s because ' + 'it has changes.\n') % self._path) + return + # we can't fully delete the repository as it may contain + # local-only history + self._ui.note(_('removing subrepo %s\n') % self._path) + self._gitcommand(['config', 'core.bare', 'true']) + for f in os.listdir(self._path): + if f == '.git': + continue + path = os.path.join(self._path, f) + if os.path.isdir(path) and not os.path.islink(path): + shutil.rmtree(path) + else: + os.remove(path) + + def archive(self, archiver, prefix): + source, revision = self._state + self._fetch(source, revision) + + # Parse git's native archive command. + # This should be much faster than manually traversing the trees + # and objects with many subprocess calls. + tarstream = self._gitcommand(['archive', revision], stream=True) + tar = tarfile.open(fileobj=tarstream, mode='r|') + for info in tar: + archiver.addfile(os.path.join(prefix, self._relpath, info.name), + info.mode, info.issym(), + tar.extractfile(info).read()) + types = { 'hg': hgsubrepo, 'svn': svnsubrepo, + 'git': gitsubrepo, }
--- a/mercurial/templatekw.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/templatekw.py Fri Dec 10 23:05:48 2010 +0100 @@ -148,7 +148,6 @@ def showbranches(**args): branch = args['ctx'].branch() if branch != 'default': - branch = encoding.tolocal(branch) return showlist('branch', [branch], plural='branches', **args) def showchildren(**args):
--- a/mercurial/ui.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/ui.py Fri Dec 10 23:05:48 2010 +0100 @@ -589,7 +589,7 @@ termination. ''' - if pos == None or not self.debugflag: + if pos is None or not self.debugflag: return if unit:
--- a/mercurial/util.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/util.py Fri Dec 10 23:05:48 2010 +0100 @@ -452,7 +452,7 @@ else: try: shutil.copyfile(src, dest) - shutil.copystat(src, dest) + shutil.copymode(src, dest) except shutil.Error, inst: raise Abort(str(inst)) @@ -822,7 +822,7 @@ self._fp.close() rename(self.temp, localpath(self.__name)) - def __del__(self): + def close(self): if not self._fp: return if not self._fp.closed: @@ -831,6 +831,9 @@ except: pass self._fp.close() + def __del__(self): + self.close() + def makedirs(name, mode=None): """recursive directory creation with parent mode inheritance""" parent = os.path.abspath(os.path.dirname(name)) @@ -1058,7 +1061,7 @@ # NOTE: unixtime = localunixtime + offset offset, date = timezone(string), string - if offset != None: + if offset is not None: date = " ".join(string.split()[:-1]) # add missing elements from defaults @@ -1334,15 +1337,26 @@ #### naming convention of below implementation follows 'textwrap' module class MBTextWrapper(textwrap.TextWrapper): + """ + Extend TextWrapper for double-width characters. + + Some Asian characters use two terminal columns instead of one. + A good example of this behavior can be seen with u'\u65e5\u672c', + the two Japanese characters for "Japan": + len() returns 2, but when printed to a terminal, they eat 4 columns. + + (Note that this has nothing to do whatsoever with unicode + representation, or encoding of the underlying string) + """ def __init__(self, **kwargs): textwrap.TextWrapper.__init__(self, **kwargs) def _cutdown(self, str, space_left): l = 0 ucstr = unicode(str, encoding.encoding) - w = unicodedata.east_asian_width + colwidth = unicodedata.east_asian_width for i in xrange(len(ucstr)): - l += w(ucstr[i]) in 'WFA' and 2 or 1 + l += colwidth(ucstr[i]) in 'WFA' and 2 or 1 if space_left < l: return (ucstr[:i].encode(encoding.encoding), ucstr[i:].encode(encoding.encoding))
--- a/mercurial/verify.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/verify.py Fri Dec 10 23:05:48 2010 +0100 @@ -34,7 +34,7 @@ raise util.Abort(_("cannot verify bundle or remote repos")) def err(linkrev, msg, filename=None): - if linkrev != None: + if linkrev is not None: badrevs.add(linkrev) else: linkrev = '?'
--- a/mercurial/wireproto.py Fri Dec 10 01:30:16 2010 +0100 +++ b/mercurial/wireproto.py Fri Dec 10 23:05:48 2010 +0100 @@ -25,7 +25,7 @@ class wirerepository(repo.repository): def lookup(self, key): self.requirecap('lookup', _('look up remote revision')) - d = self._call("lookup", key=key) + d = self._call("lookup", key=encoding.fromlocal(key)) success, data = d[:-1].split(" ", 1) if int(success): return bin(data) @@ -44,14 +44,7 @@ branchmap = {} for branchpart in d.splitlines(): branchname, branchheads = branchpart.split(' ', 1) - branchname = urllib.unquote(branchname) - # Earlier servers (1.3.x) send branch names in (their) local - # charset. The best we can do is assume it's identical to our - # own local charset, in case it's not utf-8. - try: - branchname.decode('utf-8') - except UnicodeDecodeError: - branchname = encoding.fromlocal(branchname) + branchname = encoding.tolocal(urllib.unquote(branchname)) branchheads = decodelist(branchheads) branchmap[branchname] = branchheads return branchmap @@ -83,17 +76,20 @@ if not self.capable('pushkey'): return False d = self._call("pushkey", - namespace=namespace, key=key, old=old, new=new) + namespace=encoding.fromlocal(namespace), + key=encoding.fromlocal(key), + old=encoding.fromlocal(old), + new=encoding.fromlocal(new)) return bool(int(d)) def listkeys(self, namespace): if not self.capable('pushkey'): return {} - d = self._call("listkeys", namespace=namespace) + d = self._call("listkeys", namespace=encoding.fromlocal(namespace)) r = {} for l in d.splitlines(): k, v = l.split('\t') - r[k.decode('string-escape')] = v.decode('string-escape') + r[encoding.tolocal(k)] = encoding.tolocal(v) return r def stream_out(self): @@ -162,7 +158,7 @@ branchmap = repo.branchmap() heads = [] for branch, nodes in branchmap.iteritems(): - branchname = urllib.quote(branch) + branchname = urllib.quote(encoding.fromlocal(branch)) branchnodes = encodelist(nodes) heads.append('%s %s' % (branchname, branchnodes)) return '\n'.join(heads) @@ -213,14 +209,14 @@ return "capabilities: %s\n" % (capabilities(repo, proto)) def listkeys(repo, proto, namespace): - d = pushkeymod.list(repo, namespace).items() - t = '\n'.join(['%s\t%s' % (k.encode('string-escape'), - v.encode('string-escape')) for k, v in d]) + d = pushkeymod.list(repo, encoding.tolocal(namespace)).items() + t = '\n'.join(['%s\t%s' % (encoding.fromlocal(k), encoding.fromlocal(v)) + for k, v in d]) return t def lookup(repo, proto, key): try: - r = hex(repo.lookup(key)) + r = hex(repo.lookup(encoding.tolocal(key))) success = 1 except Exception, inst: r = str(inst) @@ -228,7 +224,21 @@ return "%s %s\n" % (success, r) def pushkey(repo, proto, namespace, key, old, new): - r = pushkeymod.push(repo, namespace, key, old, new) + # compatibility with pre-1.8 clients which were accidentally + # sending raw binary nodes rather than utf-8-encoded hex + if len(new) == 20 and new.encode('string-escape') != new: + # looks like it could be a binary node + try: + u = new.decode('utf-8') + new = encoding.tolocal(new) # but cleanly decodes as UTF-8 + except UnicodeDecodeError: + pass # binary, leave unmodified + else: + new = encoding.tolocal(new) # normal path + + r = pushkeymod.push(repo, + encoding.tolocal(namespace), encoding.tolocal(key), + encoding.tolocal(old), new) return '%s\n' % int(r) def _allowstream(ui):
--- a/tests/run-tests.py Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/run-tests.py Fri Dec 10 23:05:48 2010 +0100 @@ -504,7 +504,8 @@ vlog("# Running", cmd) exitcode, output = run(cmd, options, replacements) # do not merge output if skipped, return hghave message instead - if exitcode == SKIPPED_STATUS: + # similarly, with --debug, output is None + if exitcode == SKIPPED_STATUS or output is None: return exitcode, output finally: os.remove(name) @@ -593,7 +594,7 @@ tochild.close() output = fromchild.read() ret = fromchild.close() - if ret == None: + if ret is None: ret = 0 else: proc = Popen4(cmd) @@ -713,7 +714,7 @@ # If we're not in --debug mode and reference output file exists, # check test output against it. if options.debug: - refout = None # to match out == None + refout = None # to match "out is None" elif os.path.exists(ref): f = open(ref, "r") refout = splitnewlines(f.read())
--- a/tests/test-check-code.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-check-code.t Fri Dec 10 23:05:48 2010 +0100 @@ -34,7 +34,7 @@ gratuitous whitespace in () or [] ./wrong.py:2: > del(arg2) - del isn't a function + Python keyword is not a function ./wrong.py:3: > return ( 5+6, 9) missing whitespace in expression @@ -52,3 +52,44 @@ > y = format(x) any/all/format not available in Python 2.4 [1] + + $ cat > is-op.py <<EOF + > # is-operator comparing number or string literal + > x = None + > y = x is 'foo' + > y = x is "foo" + > y = x is 5346 + > y = x is -6 + > y = x is not 'foo' + > y = x is not "foo" + > y = x is not 5346 + > y = x is not -6 + > EOF + + $ "$check_code" ./is-op.py + ./is-op.py:3: + > y = x is 'foo' + object comparison with literal + ./is-op.py:4: + > y = x is "foo" + object comparison with literal + ./is-op.py:5: + > y = x is 5346 + object comparison with literal + ./is-op.py:6: + > y = x is -6 + object comparison with literal + ./is-op.py:7: + > y = x is not 'foo' + object comparison with literal + ./is-op.py:8: + > y = x is not "foo" + object comparison with literal + ./is-op.py:9: + > y = x is not 5346 + object comparison with literal + ./is-op.py:10: + > y = x is not -6 + object comparison with literal + [1] +
--- a/tests/test-clone-failure.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-clone-failure.t Fri Dec 10 23:05:48 2010 +0100 @@ -39,7 +39,6 @@ > rm a > else > echo "abort: repository a not found!" - > echo 255 > fi abort: repository a not found!
--- a/tests/test-confused-revert.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-confused-revert.t Fri Dec 10 23:05:48 2010 +0100 @@ -58,8 +58,8 @@ Revert should fail: - $ hg revert --all - abort: uncommitted merge - please provide a specific revision + $ hg revert + abort: uncommitted merge - use "hg update", see "hg help revert" [255] Revert should be ok now:
--- a/tests/test-convert.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-convert.t Fri Dec 10 23:05:48 2010 +0100 @@ -40,16 +40,16 @@ have the following effects: --branchsort convert from parent to child revision when possible, which - means branches are usually converted one after the other. It - generates more compact repositories. + means branches are usually converted one after the other. + It generates more compact repositories. --datesort sort revisions by date. Converted repositories have good- looking changelogs but are often an order of magnitude larger than the same ones generated by --branchsort. --sourcesort try to preserve source revisions order, only supported by Mercurial sources. - If <REVMAP> isn't given, it will be put in a default location - (<dest>/.hg/shamap by default). The <REVMAP> is a simple text file that + If "REVMAP" isn't given, it will be put in a default location + ("<dest>/.hg/shamap" by default). The "REVMAP" is a simple text file that maps each source commit ID to the destination ID for that revision, like so: @@ -123,16 +123,19 @@ Mercurial Source '''''''''''''''' - --config convert.hg.ignoreerrors=False (boolean) - ignore integrity errors when reading. Use it to fix Mercurial - repositories with missing revlogs, by converting from and to - Mercurial. + The Mercurial source recognizes the following configuration options, which + you can set on the command line with "--config": - --config convert.hg.saverev=False (boolean) - store original revision ID in changeset (forces target IDs to change) - - --config convert.hg.startrev=0 (hg revision identifier) - convert start revision and its descendants + convert.hg.ignoreerrors + ignore integrity errors when reading. Use it to fix Mercurial + repositories with missing revlogs, by converting from and to + Mercurial. Default is False. + convert.hg.saverev + store original. revision ID in changeset (forces target IDs to + change). It takes and boolean argument and defaults to False. + convert.hg.startrev + convert start revision and its descendants. It takes a hg + revision identifier and defaults to 0. CVS Source '''''''''' @@ -140,46 +143,45 @@ CVS source will use a sandbox (i.e. a checked-out copy) from CVS to indicate the starting point of what will be converted. Direct access to the repository files is not needed, unless of course the repository is - :local:. The conversion uses the top level directory in the sandbox to + ":local:". The conversion uses the top level directory in the sandbox to find the CVS repository, and then uses CVS rlog commands to find files to convert. This means that unless a filemap is given, all files under the starting directory will be converted, and that any directory reorganization in the CVS sandbox is ignored. - The options shown are the defaults. - - --config convert.cvsps.cache=True (boolean) - Set to False to disable remote log caching, for testing and debugging - purposes. - - --config convert.cvsps.fuzz=60 (integer) - Specify the maximum time (in seconds) that is allowed between commits - with identical user and log message in a single changeset. When very - large files were checked in as part of a changeset then the default - may not be long enough. + The following options can be used with "--config": - --config convert.cvsps.mergeto='{{mergetobranch ([-\w]+)}}' - Specify a regular expression to which commit log messages are matched. - If a match occurs, then the conversion process will insert a dummy - revision merging the branch on which this log message occurs to the - branch indicated in the regex. - - --config convert.cvsps.mergefrom='{{mergefrombranch ([-\w]+)}}' - Specify a regular expression to which commit log messages are matched. - If a match occurs, then the conversion process will add the most - recent revision on the branch indicated in the regex as the second - parent of the changeset. - - --config hook.cvslog - Specify a Python function to be called at the end of gathering the CVS - log. The function is passed a list with the log entries, and can - modify the entries in-place, or add or delete them. - - --config hook.cvschangesets - Specify a Python function to be called after the changesets are - calculated from the the CVS log. The function is passed a list with - the changeset entries, and can modify the changesets in-place, or add - or delete them. + convert.cvsps.cache + Set to False to disable remote log caching, for testing and + debugging purposes. Default is True. + convert.cvsps.fuzz + Specify the maximum time (in seconds) that is allowed between + commits with identical user and log message in a single + changeset. When very large files were checked in as part of a + changeset then the default may not be long enough. The default + is 60. + convert.cvsps.mergeto + Specify a regular expression to which commit log messages are + matched. If a match occurs, then the conversion process will + insert a dummy revision merging the branch on which this log + message occurs to the branch indicated in the regex. Default + is "{{mergetobranch ([-\w]+)}}" + convert.cvsps.mergefrom + Specify a regular expression to which commit log messages are + matched. If a match occurs, then the conversion process will + add the most recent revision on the branch indicated in the + regex as the second parent of the changeset. Default is + "{{mergefrombranch ([-\w]+)}}" + hook.cvslog + Specify a Python function to be called at the end of gathering + the CVS log. The function is passed a list with the log + entries, and can modify the entries in-place, or add or delete + them. + hook.cvschangesets + Specify a Python function to be called after the changesets + are calculated from the the CVS log. The function is passed a + list with the changeset entries, and can modify the changesets + in-place, or add or delete them. An additional "debugcvsps" Mercurial command allows the builtin changeset merging code to be run without doing a conversion. Its parameters and @@ -199,21 +201,22 @@ them to paths relative to the source URL, or leave them blank to disable auto detection. - --config convert.svn.branches=branches (directory name) - specify the directory containing branches + The following options can be set with "--config": - --config convert.svn.tags=tags (directory name) - specify the directory containing tags - - --config convert.svn.trunk=trunk (directory name) - specify the name of the trunk branch + convert.svn.branches + specify the directory containing branches. The defaults is + "branches". + convert.svn.tags + specify the directory containing tags. The default is "tags". + convert.svn.trunk + specify the name of the trunk branch The defauls is "trunk". Source history can be retrieved starting at a specific revision, instead of being integrally converted. Only single branch conversions are supported. - --config convert.svn.startrev=0 (svn revision number) - specify start Subversion revision. + convert.svn.startrev + specify start Subversion revision number. The default is 0. Perforce Source ''''''''''''''' @@ -222,25 +225,27 @@ specification as source. It will convert all files in the source to a flat Mercurial repository, ignoring labels, branches and integrations. Note that when a depot path is given you then usually should specify a target - directory, because otherwise the target may be named ...-hg. + directory, because otherwise the target may be named "...-hg". It is possible to limit the amount of source history to be converted by - specifying an initial Perforce revision. + specifying an initial Perforce revision: - --config convert.p4.startrev=0 (perforce changelist number) - specify initial Perforce revision. + convert.p4.startrev + specify initial Perforce revision, a Perforce changelist + number). Mercurial Destination ''''''''''''''''''''' - --config convert.hg.clonebranches=False (boolean) - dispatch source branches in separate clones. + The following options are supported: - --config convert.hg.tagsbranch=default (branch name) - tag revisions branch name - - --config convert.hg.usebranchnames=True (boolean) - preserve branch names + convert.hg.clonebranches + dispatch source branches in separate clones. The default is + False. + convert.hg.tagsbranch + branch name for tag revisions, defaults to "default". + convert.hg.usebranchnames + preserve branch names. The default is True options:
--- a/tests/test-demandimport.py Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-demandimport.py Fri Dec 10 23:05:48 2010 +0100 @@ -8,6 +8,7 @@ l = repr(obj) l = rsub("0x[0-9a-fA-F]+", "0x?", l) l = rsub("from '.*'", "from '?'", l) + l = rsub("'<[a-z]*>'", "'<whatever>'", l) return l import os
--- a/tests/test-demandimport.py.out Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-demandimport.py.out Fri Dec 10 23:05:48 2010 +0100 @@ -11,5 +11,5 @@ fred.sub = <function sub at 0x?> fred = <proxied module 're'> re = <unloaded module 'sys'> -re.stderr = <open file '<stderr>', mode 'w' at 0x?> +re.stderr = <open file '<whatever>', mode 'w' at 0x?> re = <proxied module 'sys'>
--- a/tests/test-doctest.py Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-doctest.py Fri Dec 10 23:05:48 2010 +0100 @@ -13,8 +13,8 @@ import mercurial.match doctest.testmod(mercurial.match) -import mercurial.url -doctest.testmod(mercurial.url) +import mercurial.encoding +doctest.testmod(mercurial.encoding) import hgext.convert.cvsps doctest.testmod(hgext.convert.cvsps)
--- a/tests/test-encoding.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-encoding.t Fri Dec 10 23:05:48 2010 +0100 @@ -240,6 +240,4 @@ abort: decoding near '\xe9': 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)! (esc) [255] $ cp latin-1-tag .hg/branch - $ HGENCODING=latin-1 hg ci -m 'should fail' - abort: branch name not in UTF-8! - [255] + $ HGENCODING=latin-1 hg ci -m 'auto-promote legacy name'
--- a/tests/test-hardlinks-safety.t Fri Dec 10 01:30:16 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -some implementations of cp can't create hardlinks - - $ cat > cp.py <<EOF - > from mercurial import util - > import sys - > util.copyfiles(sys.argv[1], sys.argv[2], hardlink=True) - > EOF - -Test hardlinking outside hg: - - $ mkdir x - $ echo foo > x/a - - $ python cp.py x y - $ echo bar >> y/a - -No diff if hardlink: - - $ diff x/a y/a - -Test mq hardlinking: - - $ echo "[extensions]" >> $HGRCPATH - $ echo "mq=" >> $HGRCPATH - - $ hg init a - $ cd a - - $ hg qimport -n foo - << EOF - > # HG changeset patch - > # Date 1 0 - > diff -r 2588a8b53d66 a - > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 - > +++ b/a Wed Jul 23 15:54:29 2008 +0200 - > @@ -0,0 +1,1 @@ - > +a - > EOF - adding foo to series file - - $ hg qpush - applying foo - now at: foo - - $ cd .. - $ python cp.py a b - $ cd b - - $ hg qimport -n bar - << EOF - > # HG changeset patch - > # Date 2 0 - > diff -r 2588a8b53d66 a - > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 - > +++ b/b Wed Jul 23 15:54:29 2008 +0200 - > @@ -0,0 +1,1 @@ - > +b - > EOF - adding bar to series file - - $ hg qpush - applying bar - now at: bar - - $ cat .hg/patches/status - 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo - 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar - - $ cat .hg/patches/series - foo - bar - - $ cat ../a/.hg/patches/status - 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo - - $ cat ../a/.hg/patches/series - foo - -Test tags hardlinking: - - $ hg qdel -r qbase:qtip - patch foo finalized without changeset message - patch bar finalized without changeset message - - $ hg tag -l lfoo - $ hg tag foo - - $ cd .. - $ python cp.py b c - $ cd c - - $ hg tag -l -r 0 lbar - $ hg tag -r 0 bar - - $ cat .hgtags - 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo - 430ed4828a74fa4047bc816a25500f7472ab4bfe bar - - $ cat .hg/localtags - 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo - 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar - - $ cat ../b/.hgtags - 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo - - $ cat ../b/.hg/localtags - 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo -
--- a/tests/test-hardlinks.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-hardlinks.t Fri Dec 10 23:05:48 2010 +0100 @@ -10,6 +10,19 @@ > find $1 -type f | python $TESTTMP/nlinks.py > } +Some implementations of cp can't create hardlinks (replaces 'cp -al' on Linux): + + $ cat > linkcp.py <<EOF + > from mercurial import util + > import sys + > util.copyfiles(sys.argv[1], sys.argv[2], hardlink=True) + > EOF + + $ linkcp() + > { + > python $TESTTMP/linkcp.py $1 $2 + > } + Prepare repo r1: $ mkdir r1 @@ -152,3 +165,167 @@ 1 r2/.hg/store/data/f1.i 1 r2/.hg/store/fncache + + $ cd r3 + $ hg tip --template '{rev}:{node|short}\n' + 11:a6451b6bc41f + $ echo bla > f1 + $ hg ci -m1 + $ cd .. + +Create hardlinked copy r4 of r3 (on Linux, we would call 'cp -al'): + + $ linkcp r3 r4 + +r4 has hardlinks in the working dir (not just inside .hg): + + $ nlinksdir r4 + 2 r4/.hg/00changelog.i + 2 r4/.hg/branch + 2 r4/.hg/branchheads.cache + 2 r4/.hg/dirstate + 2 r4/.hg/hgrc + 2 r4/.hg/last-message.txt + 2 r4/.hg/requires + 2 r4/.hg/store/00changelog.i + 2 r4/.hg/store/00manifest.i + 2 r4/.hg/store/data/d1/f2.d + 2 r4/.hg/store/data/d1/f2.i + 2 r4/.hg/store/data/f1.i + 2 r4/.hg/store/fncache + 2 r4/.hg/store/undo + 2 r4/.hg/tags.cache + 2 r4/.hg/undo.branch + 2 r4/.hg/undo.desc + 2 r4/.hg/undo.dirstate + 2 r4/d1/data1 + 2 r4/d1/f2 + 2 r4/f1 + +Update back to revision 11 in r4 should break hardlink of file f1: + + $ hg -R r4 up 11 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + + $ nlinksdir r4 + 2 r4/.hg/00changelog.i + 1 r4/.hg/branch + 2 r4/.hg/branchheads.cache + 1 r4/.hg/dirstate + 2 r4/.hg/hgrc + 2 r4/.hg/last-message.txt + 2 r4/.hg/requires + 2 r4/.hg/store/00changelog.i + 2 r4/.hg/store/00manifest.i + 2 r4/.hg/store/data/d1/f2.d + 2 r4/.hg/store/data/d1/f2.i + 2 r4/.hg/store/data/f1.i + 2 r4/.hg/store/fncache + 2 r4/.hg/store/undo + 2 r4/.hg/tags.cache + 2 r4/.hg/undo.branch + 2 r4/.hg/undo.desc + 2 r4/.hg/undo.dirstate + 2 r4/d1/data1 + 2 r4/d1/f2 + 1 r4/f1 + + +Test hardlinking outside hg: + + $ mkdir x + $ echo foo > x/a + + $ linkcp x y + $ echo bar >> y/a + +No diff if hardlink: + + $ diff x/a y/a + +Test mq hardlinking: + + $ echo "[extensions]" >> $HGRCPATH + $ echo "mq=" >> $HGRCPATH + + $ hg init a + $ cd a + + $ hg qimport -n foo - << EOF + > # HG changeset patch + > # Date 1 0 + > diff -r 2588a8b53d66 a + > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 + > +++ b/a Wed Jul 23 15:54:29 2008 +0200 + > @@ -0,0 +1,1 @@ + > +a + > EOF + adding foo to series file + + $ hg qpush + applying foo + now at: foo + + $ cd .. + $ linkcp a b + $ cd b + + $ hg qimport -n bar - << EOF + > # HG changeset patch + > # Date 2 0 + > diff -r 2588a8b53d66 a + > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 + > +++ b/b Wed Jul 23 15:54:29 2008 +0200 + > @@ -0,0 +1,1 @@ + > +b + > EOF + adding bar to series file + + $ hg qpush + applying bar + now at: bar + + $ cat .hg/patches/status + 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo + 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar + + $ cat .hg/patches/series + foo + bar + + $ cat ../a/.hg/patches/status + 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo + + $ cat ../a/.hg/patches/series + foo + +Test tags hardlinking: + + $ hg qdel -r qbase:qtip + patch foo finalized without changeset message + patch bar finalized without changeset message + + $ hg tag -l lfoo + $ hg tag foo + + $ cd .. + $ linkcp b c + $ cd c + + $ hg tag -l -r 0 lbar + $ hg tag -r 0 bar + + $ cat .hgtags + 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo + 430ed4828a74fa4047bc816a25500f7472ab4bfe bar + + $ cat .hg/localtags + 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo + 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar + + $ cat ../b/.hgtags + 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo + + $ cat ../b/.hg/localtags + 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo +
--- a/tests/test-import.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-import.t Fri Dec 10 23:05:48 2010 +0100 @@ -437,6 +437,13 @@ $ hg revert -a reverting a + +import with --no-commit should have written .hg/last-message.txt + + $ cat .hg/last-message.txt + change (no-eol) + + test fuzziness with eol=auto $ hg --config patch.eol=auto import --no-commit -v tip.patch
--- a/tests/test-minirst.py Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-minirst.py Fri Dec 10 23:05:48 2010 +0100 @@ -120,16 +120,19 @@ There is support for simple option lists, but only with long options: ---all Output all. ---both Output both (this description is - quite long). ---long Output all day long. +-X, --exclude filter an option with a short and long option with an argument +-I, --include an option with both a short option and a long option +--all Output all. +--both Output both (this description is + quite long). +--long Output all day long. ---par This option has two paragraphs in its description. - This is the first. +--par This option has two paragraphs in its description. + This is the first. - This is the second. Blank lines may be omitted between - options (as above) or left in (as here). + This is the second. Blank lines may be omitted between + options (as above) or left in (as here). + The next paragraph looks like an option list, but lacks the two-space marker after the option. It is treated as a normal paragraph: @@ -221,6 +224,10 @@ .. An indented comment Some indented text. + +.. + +Empty comment above """ debugformat('comments', comments, 30)
--- a/tests/test-minirst.py.out Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-minirst.py.out Fri Dec 10 23:05:48 2010 +0100 @@ -180,14 +180,20 @@ There is support for simple option lists, but only with long options: ---all Output all. ---both Output both (this description is quite long). ---long Output all day long. ---par This option has two paragraphs in its - description. This is the first. + -X --exclude filter an option with a short and long option + with an argument + -I --include an option with both a short option and + a long option + --all Output all. + --both Output both (this description is quite + long). + --long Output all day long. + --par This option has two paragraphs in its + description. This is the first. - This is the second. Blank lines may be omitted - between options (as above) or left in (as here). + This is the second. Blank lines may + be omitted between options (as above) + or left in (as here). The next paragraph looks like an option list, but lacks the two-space marker after the option. It is treated as a normal @@ -202,23 +208,62 @@ option lists, but only with long options: ---all Output all. ---both Output both (this - description is - quite long). ---long Output all day - long. ---par This option has two - paragraphs in its - description. This - is the first. + -X --exclude filter an + option + with a + short + and + long + option + with an + argumen + t + -I --include an + option + with + both a + short + option + and a + long + option + --all Output + all. + --both Output + both + (this d + escript + ion is + quite + long). + --long Output + all day + long. + --par This + option + has two + paragra + phs in + its des + criptio + n. This + is the + first. - This is the second. - Blank lines may be - omitted between - options (as above) - or left in (as - here). + This is + the + second. + Blank + lines + may be + omitted + between + options + (as + above) + or left + in (as + here). The next paragraph looks like an option list, but lacks the @@ -339,5 +384,7 @@ Some text. Some indented text. + +Empty comment above ----------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-mq-qpush-exact.t Fri Dec 10 23:05:48 2010 +0100 @@ -0,0 +1,290 @@ + $ echo "[extensions]" >> $HGRCPATH + $ echo "mq=" >> $HGRCPATH + $ echo "graphlog=" >> $HGRCPATH + +make a test repository that looks like this: + +o 2:28bc7b1afd6a +| +| @ 1:d7fe2034f71b +|/ +o 0/62ecad8b70e5 + + $ hg init r0 + $ cd r0 + $ touch f0 + $ hg ci -m0 -Aq + $ touch f1 + $ hg ci -m1 -Aq + + $ hg update 0 -q + $ touch f2 + $ hg ci -m2 -Aq + $ hg update 1 -q + +make some patches with a parent: 1:d7fe2034f71b -> p0 -> p1 + + $ echo cp0 >> fp0 + $ hg add fp0 + $ hg qnew p0 -d "0 0" + + $ echo cp1 >> fp1 + $ hg add fp1 + $ hg qnew p1 -d "0 0" + + $ hg qpop -aq + patch queue now empty + +qpush --exact when at the parent + + $ hg update 1 -q + $ hg qpush -e + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg qpush -e p0 + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg qpush -e p1 + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg qpush -ea + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + +qpush --exact when at another rev + + $ hg update 0 -q + $ hg qpush -e + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 0 -q + $ hg qpush -e p0 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 0 -q + $ hg qpush -e p1 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 0 -q + $ hg qpush -ea + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + +qpush --exact while crossing branches + + $ hg update 2 -q + $ hg qpush -e + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 2 -q + $ hg qpush -e p0 + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + applying p0 + now at: p0 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 2 -q + $ hg qpush -e p1 + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + + $ hg update 2 -q + $ hg qpush -ea + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + applying p0 + applying p1 + now at: p1 + $ hg parents -qr qbase + 1:d7fe2034f71b + $ hg qpop -aq + patch queue now empty + +qpush --exact --force with changes to an unpatched file + + $ hg update 1 -q + $ echo c0 >> f0 + $ hg qpush -e + abort: local changes found, refresh first + [255] + $ hg qpush -ef + applying p0 + now at: p0 + $ cat f0 + c0 + $ rm f0 + $ touch f0 + $ hg qpop -aq + patch queue now empty + + $ hg update 1 -q + $ echo c0 >> f0 + $ hg qpush -e p1 + abort: local changes found, refresh first + [255] + $ hg qpush -e p1 -f + applying p0 + applying p1 + now at: p1 + $ cat f0 + c0 + $ rm f0 + $ touch f0 + $ hg qpop -aq + patch queue now empty + +qpush --exact --force with changes to a patched file + + $ hg update 1 -q + $ echo cp0-bad >> fp0 + $ hg add fp0 + $ hg qpush -e + abort: local changes found, refresh first + [255] + $ hg qpush -ef + applying p0 + file fp0 already exists + 1 out of 1 hunks FAILED -- saving rejects to file fp0.rej + patch failed, unable to continue (try -v) + patch failed, rejects left in working dir + errors during apply, please fix and refresh p0 + [2] + $ cat fp0 + cp0-bad + $ cat fp0.rej + --- fp0 + +++ fp0 + @@ -0,0 +1,1 @@ + +cp0 + $ hg qpop -aqf + patch queue now empty + $ rm fp0 + $ rm fp0.rej + + $ hg update 1 -q + $ echo cp1-bad >> fp1 + $ hg add fp1 + $ hg qpush -e p1 + abort: local changes found, refresh first + [255] + $ hg qpush -e p1 -f + applying p0 + applying p1 + file fp1 already exists + 1 out of 1 hunks FAILED -- saving rejects to file fp1.rej + patch failed, unable to continue (try -v) + patch failed, rejects left in working dir + errors during apply, please fix and refresh p1 + [2] + $ cat fp1 + cp1-bad + $ cat fp1.rej + --- fp1 + +++ fp1 + @@ -0,0 +1,1 @@ + +cp1 + $ hg qpop -aqf + patch queue now empty + $ rm fp1 + $ rm fp1.rej + +qpush --exact when already at a patch + + $ hg update 1 + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg qpush -e p0 + applying p0 + now at: p0 + $ hg qpush -e p1 + abort: cannot push --exact with applied patches + [255] + $ hg qpop -aq + patch queue now empty + +qpush --exact --move should fail + + $ hg qpush -e --move p1 + abort: cannot use --exact and --move together + [255] + +qpush --exact a patch without a parent recorded + + $ hg qpush -q + now at: p0 + $ grep -v '# Parent' .hg/patches/p0 > p0.new + $ mv p0.new .hg/patches/p0 + $ hg qpop -aq + patch queue now empty + $ hg qpush -e + abort: p0 does not have a parent recorded + [255] + $ hg qpush -e p0 + abort: p0 does not have a parent recorded + [255] + $ hg qpush -e p1 + abort: p0 does not have a parent recorded + [255] + $ hg qpush -ea + abort: p0 does not have a parent recorded + [255] +
--- a/tests/test-no-symlinks Fri Dec 10 01:30:16 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -#!/bin/sh - -"$TESTDIR/hghave" no-symlink || exit 80 - -# The following script was used to create the bundle: -# -# hg init symlinks -# cd symlinks -# echo a > a -# mkdir d -# echo b > d/b -# ln -s a a.lnk -# ln -s d/b d/b.lnk -# hg ci -Am t -# hg bundle --base null ../test-no-symlinks.hg - -# Extract a symlink on a platform not supporting them -echo % unbundle -hg init t -cd t -hg pull -q "$TESTDIR/test-no-symlinks.hg" -hg update - -cat a.lnk && echo -cat d/b.lnk && echo - -# Copy a symlink and move another -echo % move and copy -hg copy a.lnk d/a2.lnk -hg mv d/b.lnk b2.lnk -hg ci -Am copy -cat d/a2.lnk && echo -cat b2.lnk && echo - -# Bundle and extract again -echo % bundle -hg bundle --base null ../symlinks.hg -cd .. - -hg init t2 -cd t2 -hg pull ../symlinks.hg -hg update - -cat a.lnk && echo -cat d/a2.lnk && echo -cat b2.lnk && echo
--- a/tests/test-no-symlinks.out Fri Dec 10 01:30:16 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -% unbundle -4 files updated, 0 files merged, 0 files removed, 0 files unresolved -a -d/b -% move and copy -a -d/b -% bundle -2 changesets found -pulling from ../symlinks.hg -requesting all changes -adding changesets -adding manifests -adding file changes -added 2 changesets with 6 changes to 6 files -(run 'hg update' to get a working copy) -5 files updated, 0 files merged, 0 files removed, 0 files unresolved -a -a -d/b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-no-symlinks.t Fri Dec 10 23:05:48 2010 +0100 @@ -0,0 +1,59 @@ + $ "$TESTDIR/hghave" no-symlink || exit 80 + +# The following script was used to create the bundle: +# +# hg init symlinks +# cd symlinks +# echo a > a +# mkdir d +# echo b > d/b +# ln -s a a.lnk +# ln -s d/b d/b.lnk +# hg ci -Am t +# hg bundle --base null ../test-no-symlinks.hg + +Extract a symlink on a platform not supporting them + + $ hg init t + $ cd t + $ hg pull -q "$TESTDIR/test-no-symlinks.hg" + $ hg update + 4 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cat a.lnk && echo + a + $ cat d/b.lnk && echo + d/b + +Copy a symlink and move another + + $ hg copy a.lnk d/a2.lnk + $ hg mv d/b.lnk b2.lnk + $ hg ci -Am copy + $ cat d/a2.lnk && echo + a + $ cat b2.lnk && echo + d/b + +Bundle and extract again + + $ hg bundle --base null ../symlinks.hg + 2 changesets found + $ cd .. + $ hg init t2 + $ cd t2 + $ hg pull ../symlinks.hg + pulling from ../symlinks.hg + requesting all changes + adding changesets + adding manifests + adding file changes + added 2 changesets with 6 changes to 6 files + (run 'hg update' to get a working copy) + $ hg update + 5 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cat a.lnk && echo + a + $ cat d/a2.lnk && echo + a + $ cat b2.lnk && echo + d/b
--- a/tests/test-parentrevspec.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-parentrevspec.t Fri Dec 10 23:05:48 2010 +0100 @@ -69,12 +69,12 @@ 6^^^^^: 0 6^^^^^^: -1 6^1: 5 - 6^2: abort: unknown revision '6^2'! + 6^2: hg: parse error at 1: syntax error 6^^2: 4 6^1^2: 4 - 6^^3: abort: unknown revision '6^^3'! + 6^^3: hg: parse error at 1: syntax error $ lookup "6~" "6~1" "6~2" "6~3" "6~4" "6~5" "6~42" "6~1^2" "6~1^2~2" - 6~: abort: unknown revision '6~'! + 6~: hg: parse error at 1: syntax error 6~1: 5 6~2: 3 6~3: 2 @@ -102,4 +102,4 @@ $ hg tag -l -r 2 "foo^bar" $ lookup "foo^bar" "foo^bar^" foo^bar: 2 - foo^bar^: abort: unknown revision 'foo^bar^'! + foo^bar^: hg: parse error at 3: syntax error
--- a/tests/test-push-warn.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-push-warn.t Fri Dec 10 23:05:48 2010 +0100 @@ -30,6 +30,23 @@ (you should pull and merge or use push -f to force) [255] + $ hg push --debug ../a + pushing to ../a + searching for changes + examining 1c9246a22a0a:d8d565842d04 + found incomplete branch 1c9246a22a0a:d8d565842d04 + searching: 1 queries + narrowing 1:1 d8d565842d04 + found new branch changeset 1c9246a22a0a + found new changesets starting at 1c9246a22a0a + 1 total queries + common changesets up to d8d565842d04 + new remote heads on branch 'default' + new remote head 1e108cc5548c + abort: push creates new remote heads on branch 'default'! + (you should pull and merge or use push -f to force) + [255] + $ hg pull ../a pulling from ../a searching for changes
--- a/tests/test-record.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-record.t Fri Dec 10 23:05:48 2010 +0100 @@ -883,7 +883,7 @@ (branch merge, don't forget to commit) $ hg record -m'will abort' - abort: cannot partially commit a merge (use hg commit instead) + abort: cannot partially commit a merge (use "hg commit" instead) [255] $ hg up -C
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-revset-dirstate-parents.t Fri Dec 10 23:05:48 2010 +0100 @@ -0,0 +1,52 @@ + $ HGENCODING=utf-8 + $ export HGENCODING + + $ try() { + > hg debugrevspec --debug $@ + > } + + $ log() { + > hg log --template '{rev}\n' -r "$1" + > } + + $ hg init repo + $ cd repo + + $ try 'p1()' + ('func', ('symbol', 'p1'), None) + $ try 'p2()' + ('func', ('symbol', 'p2'), None) + $ try 'parents()' + ('func', ('symbol', 'parents'), None) + +null revision + $ log 'p1()' + $ log 'p2()' + $ log 'parents()' + +working dir with a single parent + $ echo a > a + $ hg ci -Aqm0 + $ log 'p1()' + 0 + $ log 'tag() and p1()' + $ log 'p2()' + $ log 'parents()' + 0 + $ log 'tag() and parents()' + +merge in progress + $ echo b > b + $ hg ci -Aqm1 + $ hg up -q 0 + $ echo c > c + $ hg ci -Aqm2 + $ hg merge -q + $ log 'p1()' + 2 + $ log 'p2()' + 1 + $ log 'tag() and p2()' + $ log 'parents()' + 1 + 2
--- a/tests/test-ssh.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-ssh.t Fri Dec 10 23:05:48 2010 +0100 @@ -214,7 +214,7 @@ $ hg debugpushkey --config ui.ssh="python ../dummyssh" ssh://user@dummy/remote bookmarks foo 1160648e36cec0054048a7edc4110c6f84fde594 $ hg book -f foo - $ hg push + $ hg push --traceback pushing to ssh://user@dummy/remote searching for changes no changes found
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-subrepo-git.t Fri Dec 10 23:05:48 2010 +0100 @@ -0,0 +1,263 @@ + $ "$TESTDIR/hghave" git || exit 80 + +make git commits repeatable + + $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME + $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL + $ GIT_AUTHOR_DATE='1234567891 +0000'; export GIT_AUTHOR_DATE + $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME + $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL + $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE + +root hg repo + + $ hg init t + $ cd t + $ echo a > a + $ hg add a + $ hg commit -m a + $ cd .. + +new external git repo + + $ mkdir gitroot + $ cd gitroot + $ git init -q + $ echo g > g + $ git add g + $ git commit -q -m g + +add subrepo clone + + $ cd ../t + $ echo 's = [git]../gitroot' > .hgsub + $ git clone -q ../gitroot s + $ hg add .hgsub + $ hg commit -m 'new git subrepo' + committing subrepository $TESTTMP/t/s + $ hg debugsub + path s + source ../gitroot + revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7 + +record a new commit from upstream from a different branch + + $ cd ../gitroot + $ git checkout -q -b testing + $ echo gg >> g + $ git commit -q -a -m gg + + $ cd ../t/s + $ git pull -q >/dev/null 2>/dev/null + $ git checkout -q -b testing origin/testing >/dev/null + + $ cd .. + $ hg commit -m 'update git subrepo' + committing subrepository $TESTTMP/t/s + $ hg debugsub + path s + source ../gitroot + revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a + +make $GITROOT pushable, by replacing it with a clone with nothing checked out + + $ cd .. + $ git clone gitroot gitrootbare --bare -q + $ rm -rf gitroot + $ mv gitrootbare gitroot + +clone root + + $ cd t + $ hg clone . ../tc + updating to branch default + cloning subrepo s + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cd ../tc + $ hg debugsub + path s + source ../gitroot + revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a + +update to previous substate + + $ hg update 1 2>/dev/null + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cat s/g + g + $ hg debugsub + path s + source ../gitroot + revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7 + +clone root, make local change + + $ cd ../t + $ hg clone . ../ta + updating to branch default + cloning subrepo s + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + + $ cd ../ta + $ echo ggg >> s/g + $ hg commit -m ggg + committing subrepository $TESTTMP/ta/s + $ hg debugsub + path s + source ../gitroot + revision 79695940086840c99328513acbe35f90fcd55e57 + +clone root separately, make different local change + + $ cd ../t + $ hg clone . ../tb + updating to branch default + cloning subrepo s + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + + $ cd ../tb/s + $ echo f > f + $ git add f + $ cd .. + + $ hg commit -m f + committing subrepository $TESTTMP/tb/s + $ hg debugsub + path s + source ../gitroot + revision aa84837ccfbdfedcdcdeeedc309d73e6eb069edc + +user b push changes + + $ hg push 2>/dev/null + pushing to $TESTTMP/t + pushing branch testing of subrepo s + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + +user a pulls, merges, commits + + $ cd ../ta + $ hg pull + pulling from $TESTTMP/t + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files (+1 heads) + (run 'hg heads' to see heads, 'hg merge' to merge) + $ hg merge 2>/dev/null + pulling subrepo s + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + $ cat s/f + f + $ cat s/g + g + gg + ggg + $ hg commit -m 'merge' + committing subrepository $TESTTMP/ta/s + $ hg debugsub + path s + source ../gitroot + revision f47b465e1bce645dbf37232a00574aa1546ca8d3 + $ hg push 2>/dev/null + pushing to $TESTTMP/t + pushing branch testing of subrepo s + searching for changes + adding changesets + adding manifests + adding file changes + added 2 changesets with 2 changes to 1 files + +make upstream git changes + + $ cd .. + $ git clone -q gitroot gitclone + $ cd gitclone + $ echo ff >> f + $ git commit -q -a -m ff + $ echo fff >> f + $ git commit -q -a -m fff + $ git push origin testing 2>/dev/null + +make and push changes to hg without updating the subrepo + + $ cd ../t + $ hg clone . ../td + updating to branch default + cloning subrepo s + checking out detached HEAD in subrepo s + check out a git branch if you intend to make changes + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cd ../td + $ echo aa >> a + $ hg commit -m aa + $ hg push + pushing to $TESTTMP/t + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + +sync to upstream git, distribute changes + + $ cd ../ta + $ hg pull -u -q + $ cd s + $ git pull -q >/dev/null 2>/dev/null + $ cd .. + $ hg commit -m 'git upstream sync' + committing subrepository $TESTTMP/ta/s + $ hg debugsub + path s + source ../gitroot + revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc + $ hg push -q + + $ cd ../tb + $ hg pull -q + $ hg update 2>/dev/null + pulling subrepo s + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg debugsub + path s + source ../gitroot + revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc + +update to a revision without the subrepo, keeping the local git repository + + $ cd ../t + $ hg up 0 + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + $ ls -a s + . + .. + .git + + $ hg up 2 + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ ls -a s + . + .. + .git + g + +archive subrepos + + $ cd ../tc + $ hg pull -q + $ hg archive --subrepos -r 5 ../archive 2>/dev/null + pulling subrepo s + $ cd ../archive + $ cat s/f + f + $ cat s/g + g + gg + ggg
--- a/tests/test-win32text.t Fri Dec 10 01:30:16 2010 +0100 +++ b/tests/test-win32text.t Fri Dec 10 23:05:48 2010 +0100 @@ -9,10 +9,6 @@ > data = data.replace('\n', '\r\n') > file(path, 'wb').write(data) > EOF - $ cat > print.py <<EOF - > import sys - > print(sys.stdin.read().replace('\n', '<LF>').replace('\r', '<CR>').replace('\0', '<NUL>')) - > EOF $ echo '[hooks]' >> .hg/hgrc $ echo 'pretxncommit.crlf = python:hgext.win32text.forbidcrlf' >> .hg/hgrc $ echo 'pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf' >> .hg/hgrc @@ -369,12 +365,13 @@ $ python -c 'file("f4.bat", "wb").write("rem empty\x0D\x0A")' $ hg add f3 f4.bat $ hg ci -m 6 - $ python print.py < bin - hello<NUL><CR><LF> - $ python print.py < f3 - some<LF>text<LF> - $ python print.py < f4.bat - rem empty<CR><LF> + $ cat bin + hello\x00\r (esc) + $ cat f3 + some + text + $ cat f4.bat + rem empty\r (esc) $ echo $ echo '[extensions]' >> .hg/hgrc @@ -405,38 +402,39 @@ tip $ rm f3 f4.bat bin - $ hg co -C 2>&1 | python -c 'import sys, os; sys.stdout.write(sys.stdin.read().replace(os.getcwd(), "...."))' + $ hg co -C WARNING: f4.bat already has CRLF line endings and does not need EOL conversion by the win32text plugin. Before your next commit, please reconsider your encode/decode settings in - Mercurial.ini or ..../.hg/hgrc. + Mercurial.ini or $TESTTMP/t/.hg/hgrc. 3 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ python print.py < bin - hello<NUL><CR><LF> - $ python print.py < f3 - some<CR><LF>text<CR><LF> - $ python print.py < f4.bat - rem empty<CR><LF> + $ cat bin + hello\x00\r (esc) + $ cat f3 + some\r (esc) + text\r (esc) + $ cat f4.bat + rem empty\r (esc) $ echo $ python -c 'file("f5.sh", "wb").write("# empty\x0D\x0A")' $ hg add f5.sh $ hg ci -m 7 - $ python print.py < f5.sh - # empty<CR><LF> - $ hg cat f5.sh | python print.py - # empty<LF> + $ cat f5.sh + # empty\r (esc) + $ hg cat f5.sh + # empty $ echo '% just linefeed' > linefeed $ hg ci -qAm 8 linefeed - $ python print.py < linefeed - % just linefeed<LF> - $ hg cat linefeed | python print.py - % just linefeed<LF> + $ cat linefeed + % just linefeed + $ hg cat linefeed + % just linefeed $ hg st -q $ hg revert -a linefeed no changes needed to linefeed - $ python print.py < linefeed - % just linefeed<LF> + $ cat linefeed + % just linefeed $ hg st -q $ echo modified >> linefeed $ hg st -q @@ -444,5 +442,5 @@ $ hg revert -a reverting linefeed $ hg st -q - $ python print.py < linefeed - % just linefeed<CR><LF> + $ cat linefeed + % just linefeed\r (esc)