Mercurial > hg
changeset 12968:609edbc7853f
merge with stable
author | Martin Geisler <mg@lazybytes.net> |
---|---|
date | Thu, 11 Nov 2010 07:23:38 +0100 |
parents | 34034e55424f (diff) 70b043405400 (current diff) |
children | 91cbba199d8b |
files | mercurial/commands.py |
diffstat | 21 files changed, 424 insertions(+), 322 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/check-code.py Wed Nov 10 17:28:24 2010 +0100 +++ b/contrib/check-code.py Thu Nov 11 07:23:38 2010 +0100 @@ -118,6 +118,9 @@ "linebreak after :"), (r'class\s[^(]:', "old-style class, use class foo(object)"), (r'^\s+del\(', "del isn't a function"), + (r'\band\(', "and isn't a function"), + (r'\bor\(', "or isn't a function"), + (r'\bnot\(', "not isn't a function"), (r'^\s+except\(', "except isn't a function"), (r',]', "unneeded trailing ',' in list"), # (r'class\s[A-Z][^\(]*\((?!Exception)',
--- a/doc/Makefile Wed Nov 10 17:28:24 2010 +0100 +++ b/doc/Makefile Thu Nov 11 07:23:38 2010 +0100 @@ -1,7 +1,8 @@ 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
--- a/hgext/convert/__init__.py Wed Nov 10 17:28:24 2010 +0100 +++ b/hgext/convert/__init__.py Thu Nov 11 07:23:38 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/keyword.py Wed Nov 10 17:28:24 2010 +0100 +++ b/hgext/keyword.py Thu Nov 11 07:23:38 2010 +0100 @@ -170,14 +170,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 +202,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 +227,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 +240,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 +257,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 +265,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):
--- a/hgext/mq.py Wed Nov 10 17:28:24 2010 +0100 +++ b/hgext/mq.py Thu Nov 11 07:23:38 2010 +0100 @@ -1289,6 +1289,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 @@ -1296,31 +1299,31 @@ # show up in the added section for x in m: 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. for x in a: 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 = [] for x in d + r: 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,
--- a/mercurial/cmdutil.py Wed Nov 10 17:28:24 2010 +0100 +++ b/mercurial/cmdutil.py Thu Nov 11 07:23:38 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)
--- a/mercurial/commands.py Wed Nov 10 17:28:24 2010 +0100 +++ b/mercurial/commands.py Thu Nov 11 07:23:38 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) @@ -572,11 +573,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 +1030,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 +1120,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 +1144,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 +1178,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 +1438,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 +1811,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)] @@ -2200,7 +2202,7 @@ 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: @@ -2279,6 +2281,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 +2332,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 +2384,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 +2445,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 +2580,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])) @@ -2641,6 +2649,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 +2696,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) @@ -3106,7 +3113,7 @@ 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 +3722,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/context.py Wed Nov 10 17:28:24 2010 +0100 +++ b/mercurial/context.py Thu Nov 11 07:23:38 2010 +0100 @@ -603,6 +603,9 @@ def __str__(self): return str(self._parents[0]) + "+" + def __repr__(self): + return "<workingctx %s>" % str(self) + def __nonzero__(self): return True @@ -897,6 +900,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):
--- a/mercurial/demandimport.py Wed Nov 10 17:28:24 2010 +0100 +++ b/mercurial/demandimport.py Thu Nov 11 07:23:38 2010 +0100 @@ -111,7 +111,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/localrepo.py Wed Nov 10 17:28:24 2010 +0100 +++ b/mercurial/localrepo.py Thu Nov 11 07:23:38 2010 +0100 @@ -1202,8 +1202,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/minirst.py Wed Nov 10 17:28:24 2010 +0100 +++ b/mercurial/minirst.py Thu Nov 11 07:23:38 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
--- a/mercurial/patch.py Wed Nov 10 17:28:24 2010 +0100 +++ b/mercurial/patch.py Thu Nov 11 07:23:38 2010 +0100 @@ -974,7 +974,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 @@ -995,10 +995,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 @@ -1010,7 +1006,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 @@ -1032,7 +1028,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: @@ -1047,7 +1042,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 @@ -1075,9 +1069,6 @@ afile = parsefilename(x) bfile = parsefilename(l2) - if newfile: - gitworkdone = False - if newgitfile or newfile: emitfile = True state = BFILE @@ -1089,7 +1080,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 @@ -1103,13 +1094,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 @@ -1124,7 +1112,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 @@ -1137,14 +1125,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/revset.py Wed Nov 10 17:28:24 2010 +0100 +++ b/mercurial/revset.py Thu Nov 11 07:23:38 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):
--- a/mercurial/util.py Wed Nov 10 17:28:24 2010 +0100 +++ b/mercurial/util.py Thu Nov 11 07:23:38 2010 +0100 @@ -1328,15 +1328,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/tests/test-convert.t Wed Nov 10 17:28:24 2010 +0100 +++ b/tests/test-convert.t Thu Nov 11 07:23:38 2010 +0100 @@ -48,8 +48,8 @@ --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-import.t Wed Nov 10 17:28:24 2010 +0100 +++ b/tests/test-import.t Thu Nov 11 07:23:38 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-no-symlinks Wed Nov 10 17:28:24 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 Wed Nov 10 17:28:24 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 Thu Nov 11 07:23:38 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 Wed Nov 10 17:28:24 2010 +0100 +++ b/tests/test-parentrevspec.t Thu Nov 11 07:23:38 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-revset-dirstate-parents.t Thu Nov 11 07:23:38 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