Merge with i18n
authorMatt Mackall <mpm@selenic.com>
Sat, 01 May 2010 15:14:22 -0500
changeset 11077 132d783d6a87
parent 11065 76d6c19aa8ef (diff)
parent 11075 4b8fd86aba5e (current diff)
child 11078 37d1b20168d1
Merge with i18n
--- a/contrib/mercurial.spec	Fri Apr 30 17:41:09 2010 -0300
+++ b/contrib/mercurial.spec	Sat May 01 15:14:22 2010 -0500
@@ -38,8 +38,7 @@
 
 %install
 rm -rf $RPM_BUILD_ROOT
-python setup.py install --root $RPM_BUILD_ROOT --prefix %{_prefix}
-make install-doc DESTDIR=$RPM_BUILD_ROOT MANDIR=%{_mandir}
+make install DESTDIR=$RPM_BUILD_ROOT PREFIX=%{_prefix} MANDIR=%{_mandir}
 
 install contrib/hgk          $RPM_BUILD_ROOT%{_bindir}
 install contrib/convert-repo $RPM_BUILD_ROOT%{_bindir}/mercurial-convert-repo
--- a/hgext/acl.py	Fri Apr 30 17:41:09 2010 -0300
+++ b/hgext/acl.py	Sat May 01 15:14:22 2010 -0500
@@ -22,27 +22,26 @@
 Nor is it safe if remote users share an account, because then there
 is no way to distinguish them.
 
-The deny list is checked before the allow list is.
+The deny list is checked before the allow list.
 
 The allow and deny sections take key-value pairs, having a subtree pattern
 as key (with a glob syntax by default). The corresponding value can be either:
+
 1) an asterisk, to match everyone;
 2) a comma-separated list containing users and groups.
 
-Group names must be prefixed with an @ symbol.
+Group names must be prefixed with an ``@`` symbol.
 Specifying a group name has the same effect as specifying all the users in
 that group.
-The set of users for a group is taken from "grp.getgrnam"
-(see http://docs.python.org/library/grp.html#grp.getgrnam).
 
-To use this hook, configure the acl extension in your hgrc like this:
+To use this hook, configure the acl extension in your hgrc like this::
 
   [extensions]
   acl =
 
   [hooks]
 
-  # Use this if you want to check access restrictions at commit time
+  # Use this if you want to check access restrictions at commit time.
   pretxncommit.acl = python:hgext.acl.hook
   
   # Use this if you want to check access restrictions for pull, push, bundle
@@ -50,16 +49,15 @@
   pretxnchangegroup.acl = python:hgext.acl.hook
 
   [acl]
-  # Check whether the source of incoming changes is in this list
-  # ("serve" == ssh or http, "push", "pull", "bundle")
+  # Check whether the source of incoming changes is in this list where
+  # "serve" == ssh or http, and "push", "pull" and "bundle" are the
+  # corresponding hg commands.
   sources = serve
 
   [acl.deny]
   # This list is checked first. If a match is found, 'acl.allow' will not be
-  # checked.
-  # if acl.deny is not present, no users denied by default
-  # empty acl.deny = all users allowed
-  # Format for both lists: glob pattern = user4, user5, @group1
+  # checked. All users are granted access if acl.deny is not present.
+  # Format for both lists: glob pattern = user, ..., @group, ...
 
   # To match everyone, use an asterisk for the user:
   # my/glob/pattern = *
@@ -86,7 +84,7 @@
   images/** = jack, @designers
 
   # Everyone (except for "user6" - see "acl.deny" above) will have write access
-  to any file under the "resources" folder (except for 1 file. See "acl.deny"):
+  # to any file under the "resources" folder (except for 1 file. See "acl.deny"):
   src/main/resources/** = *
 
   .hgtags = release_engineer
--- a/hgext/mq.py	Fri Apr 30 17:41:09 2010 -0300
+++ b/hgext/mq.py	Sat May 01 15:14:22 2010 -0500
@@ -978,7 +978,7 @@
         raise util.Abort(_("patch %s not in series") % patch)
 
     def push(self, repo, patch=None, force=False, list=False,
-             mergeq=None, all=False):
+             mergeq=None, all=False, move=False):
         diffopts = self.diffopts()
         wlock = repo.wlock()
         try:
@@ -1034,6 +1034,15 @@
             if not force:
                 self.check_localchanges(repo)
 
+            if move:
+                try:
+                    del self.full_series[self.full_series.index(patch, start)]
+                except ValueError:
+                    raise util.Abort(_("patch '%s' not found") % patch)
+                self.full_series.insert(start, patch)
+                self.parse_series()
+                self.series_dirty = 1
+
             self.applied_dirty = 1
             if start > 0:
                 self.check_toppatch(repo)
@@ -2222,7 +2231,7 @@
         mergeq = queue(ui, repo.join(""), newpath)
         ui.warn(_("merging with queue at: %s\n") % mergeq.path)
     ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
-                 mergeq=mergeq, all=opts.get('all'))
+                 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'))
     return ret
 
 def pop(ui, repo, patch=None, **opts):
@@ -2735,8 +2744,9 @@
           ('l', 'list', None, _('list patch name in commit text')),
           ('a', 'all', None, _('apply all patches')),
           ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
-          ('n', 'name', '', _('merge queue name (DEPRECATED)'))],
-         _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
+          ('n', 'name', '', _('merge queue name (DEPRECATED)')),
+          ('', 'move', None, _('reorder patch series and apply only the patch'))],
+         _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [--move] [PATCH | INDEX]')),
     "^qrefresh":
         (refresh,
          [('e', 'edit', None, _('edit commit message')),
--- a/hgext/relink.py	Fri Apr 30 17:41:09 2010 -0300
+++ b/hgext/relink.py	Sat May 01 15:14:22 2010 -0500
@@ -116,7 +116,6 @@
     CHUNKLEN = 65536
     relinked = 0
     savedbytes = 0
-    f = ''
 
     pos = 0
     total = len(files)
--- a/mercurial/cmdutil.py	Fri Apr 30 17:41:09 2010 -0300
+++ b/mercurial/cmdutil.py	Sat May 01 15:14:22 2010 -0500
@@ -10,6 +10,7 @@
 import os, sys, errno, re, glob, tempfile
 import mdiff, bdiff, util, templater, patch, error, encoding, templatekw
 import match as _match
+import similar
 
 revrangesep = ':'
 
@@ -286,52 +287,6 @@
 def matchfiles(repo, files):
     return _match.exact(repo.root, repo.getcwd(), files)
 
-def findrenames(repo, added, removed, threshold):
-    '''find renamed files -- yields (before, after, score) tuples'''
-    copies = {}
-    ctx = repo['.']
-    for i, r in enumerate(removed):
-        repo.ui.progress(_('searching'), i, total=len(removed))
-        if r not in ctx:
-            continue
-        fctx = ctx.filectx(r)
-
-        # lazily load text
-        @util.cachefunc
-        def data():
-            orig = fctx.data()
-            return orig, mdiff.splitnewlines(orig)
-
-        def score(text):
-            if not len(text):
-                return 0.0
-            if not fctx.cmp(text):
-                return 1.0
-            if threshold == 1.0:
-                return 0.0
-            orig, lines = data()
-            # bdiff.blocks() returns blocks of matching lines
-            # count the number of bytes in each
-            equal = 0
-            matches = bdiff.blocks(text, orig)
-            for x1, x2, y1, y2 in matches:
-                for line in lines[y1:y2]:
-                    equal += len(line)
-
-            lengths = len(text) + len(orig)
-            return equal * 2.0 / lengths
-
-        for a in added:
-            bestscore = copies.get(a, (None, threshold))[1]
-            myscore = score(repo.wread(a))
-            if myscore >= bestscore:
-                copies[a] = (r, myscore)
-    repo.ui.progress(_('searching'), None)
-
-    for dest, v in copies.iteritems():
-        source, score = v
-        yield source, dest, score
-
 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
     if dry_run is None:
         dry_run = opts.get('dry_run')
@@ -366,8 +321,8 @@
             added.append(abs)
     copies = {}
     if similarity > 0:
-        for old, new, score in findrenames(repo, added + unknown,
-                                           removed + deleted, similarity):
+        for old, new, score in similar.findrenames(repo,
+                added + unknown, removed + deleted, similarity):
             if repo.ui.verbose or not m.exact(old) or not m.exact(new):
                 repo.ui.status(_('recording removal of %s as rename to %s '
                                  '(%d%% similar)\n') %
@@ -848,11 +803,11 @@
 
     def showpatch(self, node):
         if self.patch:
+            stat = self.diffopts.get('stat')
+            diffopts = patch.diffopts(self.ui, self.diffopts)
             prev = self.repo.changelog.parents(node)[0]
-            chunks = patch.diffui(self.repo, prev, node, match=self.patch,
-                                  opts=patch.diffopts(self.ui, self.diffopts))
-            for chunk, label in chunks:
-                self.ui.write(chunk, label=label)
+            diffordiffstat(self.ui, self.repo, diffopts, prev, node,
+                           match=self.patch, stat=stat)
             self.ui.write("\n")
 
     def _meaningful_parentrevs(self, log, rev):
@@ -984,7 +939,7 @@
     """
     # options
     patch = False
-    if opts.get('patch'):
+    if opts.get('patch') or opts.get('stat'):
         patch = matchfn or matchall(repo)
 
     tmpl = opts.get('template')
--- a/mercurial/commands.py	Fri Apr 30 17:41:09 2010 -0300
+++ b/mercurial/commands.py	Sat May 01 15:14:22 2010 -0500
@@ -3209,6 +3209,9 @@
     shared among repositories).
 
     See :hg:`help dates` for a list of formats valid for -d/--date.
+
+    Since tag names have priority over branch names during revision
+    lookup, using an existing branch name as a tag name is discouraged.
     """
 
     rev_ = "."
@@ -3462,6 +3465,7 @@
     ('g', 'git', None, _('use git extended diff format')),
     ('l', 'limit', '', _('limit number of changes displayed')),
     ('M', 'no-merges', None, _('do not show merges')),
+    ('', 'stat', None, _('output diffstat-style summary of changes')),
 ] + templateopts
 
 diffopts = [
--- a/mercurial/dispatch.py	Fri Apr 30 17:41:09 2010 -0300
+++ b/mercurial/dispatch.py	Sat May 01 15:14:22 2010 -0500
@@ -105,8 +105,8 @@
     except util.Abort, inst:
         ui.warn(_("abort: %s\n") % inst)
     except ImportError, inst:
+        ui.warn(_("abort: %s!\n") % inst)
         m = str(inst).split()[-1]
-        ui.warn(_("abort: could not import module %s!\n") % m)
         if m in "mpatch bdiff".split():
             ui.warn(_("(did you forget to compile extensions?)\n"))
         elif m in "zlib".split():
--- a/mercurial/localrepo.py	Fri Apr 30 17:41:09 2010 -0300
+++ b/mercurial/localrepo.py	Sat May 01 15:14:22 2010 -0500
@@ -164,9 +164,13 @@
             if c in allchars:
                 raise util.Abort(_('%r cannot be used in a tag name') % c)
 
+        branches = self.branchmap()
         for name in names:
             self.hook('pretag', throw=True, node=hex(node), tag=name,
                       local=local)
+            if name in branches:
+                self.ui.warn(_("warning: tag %s conflicts with existing"
+                " branch name\n") % name)
 
         def writetags(fp, names, munge, prevtags):
             fp.seek(0, 2)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/similar.py	Sat May 01 15:14:22 2010 -0500
@@ -0,0 +1,103 @@
+# similar.py - mechanisms for finding similar files
+#
+# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from i18n import _
+import util
+import mdiff
+import bdiff
+
+def _findexactmatches(repo, added, removed):
+    '''find renamed files that have no changes
+
+    Takes a list of new filectxs and a list of removed filectxs, and yields
+    (before, after) tuples of exact matches.
+    '''
+    numfiles = len(added) + len(removed)
+
+    # Get hashes of removed files.
+    hashes = {}
+    for i, fctx in enumerate(removed):
+        repo.ui.progress(_('searching for exact renames'), i, total=numfiles)
+        h = util.sha1(fctx.data()).digest()
+        hashes[h] = fctx
+
+    # For each added file, see if it corresponds to a removed file.
+    for i, fctx in enumerate(added):
+        repo.ui.progress(_('searching for exact renames'), i + len(removed),
+                total=numfiles)
+        h = util.sha1(fctx.data()).digest()
+        if h in hashes:
+            yield (hashes[h], fctx)
+
+    # Done
+    repo.ui.progress(_('searching for exact renames'), None)
+
+def _findsimilarmatches(repo, added, removed, threshold):
+    '''find potentially renamed files based on similar file content
+
+    Takes a list of new filectxs and a list of removed filectxs, and yields
+    (before, after, score) tuples of partial matches.
+    '''
+    copies = {}
+    for i, r in enumerate(removed):
+        repo.ui.progress(_('searching for similar files'), i, total=len(removed))
+
+        # lazily load text
+        @util.cachefunc
+        def data():
+            orig = r.data()
+            return orig, mdiff.splitnewlines(orig)
+
+        def score(text):
+            orig, lines = data()
+            # bdiff.blocks() returns blocks of matching lines
+            # count the number of bytes in each
+            equal = 0
+            matches = bdiff.blocks(text, orig)
+            for x1, x2, y1, y2 in matches:
+                for line in lines[y1:y2]:
+                    equal += len(line)
+
+            lengths = len(text) + len(orig)
+            return equal * 2.0 / lengths
+
+        for a in added:
+            bestscore = copies.get(a, (None, threshold))[1]
+            myscore = score(a.data())
+            if myscore >= bestscore:
+                copies[a] = (r, myscore)
+    repo.ui.progress(_('searching'), None)
+
+    for dest, v in copies.iteritems():
+        source, score = v
+        yield source, dest, score
+
+def findrenames(repo, added, removed, threshold):
+    '''find renamed files -- yields (before, after, score) tuples'''
+    parentctx = repo['.']
+    workingctx = repo[None]
+
+    # Zero length files will be frequently unrelated to each other, and
+    # tracking the deletion/addition of such a file will probably cause more
+    # harm than good. We strip them out here to avoid matching them later on.
+    addedfiles = set([workingctx[fp] for fp in added
+            if workingctx[fp].size() > 0])
+    removedfiles = set([parentctx[fp] for fp in removed
+            if fp in parentctx and parentctx[fp].size() > 0])
+
+    # Find exact matches.
+    for (a, b) in _findexactmatches(repo,
+            sorted(addedfiles),sorted( removedfiles)):
+        addedfiles.remove(b)
+        yield (a.path(), b.path(), 1.0)
+
+    # If the user requested similar files to be matched, search for them also.
+    if threshold < 1.0:
+        for (a, b, score) in _findsimilarmatches(repo,
+                sorted(addedfiles), sorted(removedfiles), threshold):
+            yield (a.path(), b.path(), score)
+
--- a/tests/test-acl	Fri Apr 30 17:41:09 2010 -0300
+++ b/tests/test-acl	Sat May 01 15:14:22 2010 -0500
@@ -7,7 +7,7 @@
 
     echo "Pushing as user $user"
     echo 'hgrc = """'
-    sed -e 1,2d b/.hg/hgrc | grep -v /tmp/
+    sed -e 1,2d b/.hg/hgrc | grep -v "$HGTMP"
     echo '"""'
     if test -f acl.config; then
 	echo 'acl.config = """'
--- a/tests/test-debugcomplete.out	Fri Apr 30 17:41:09 2010 -0300
+++ b/tests/test-debugcomplete.out	Sat May 01 15:14:22 2010 -0500
@@ -171,7 +171,7 @@
 export: output, switch-parent, rev, text, git, nodates
 forget: include, exclude
 init: ssh, remotecmd
-log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, style, template, include, exclude
+log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude
 merge: force, rev, preview
 pull: update, force, rev, branch, ssh, remotecmd
 push: force, rev, branch, ssh, remotecmd
@@ -210,10 +210,10 @@
 help: 
 identify: rev, num, id, branch, tags
 import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
-incoming: force, newest-first, bundle, rev, branch, patch, git, limit, no-merges, style, template, ssh, remotecmd
+incoming: force, newest-first, bundle, rev, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd
 locate: rev, print0, fullpath, include, exclude
 manifest: rev
-outgoing: force, rev, newest-first, branch, patch, git, limit, no-merges, style, template, ssh, remotecmd
+outgoing: force, rev, newest-first, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd
 parents: rev, style, template
 paths: 
 recover: 
--- a/tests/test-keyword	Fri Apr 30 17:41:09 2010 -0300
+++ b/tests/test-keyword	Sat May 01 15:14:22 2010 -0500
@@ -143,10 +143,8 @@
 cat a c
 
 echo % record
-cp "$HGRCPATH" $HGRCPATH.bak
-sed -e '1 a \foo' a > a.tmp
-mv a.tmp a
-echo bar >> a
+python -c \
+'l=open("a").readlines();l.insert(1,"foo\n");l.append("bar\n");open("a","w").writelines(l);'
 hg record -d '1 10' -m rectest<<EOF
 y
 y
--- a/tests/test-log	Fri Apr 30 17:41:09 2010 -0300
+++ b/tests/test-log	Sat May 01 15:14:22 2010 -0500
@@ -121,6 +121,9 @@
 echo '% log -p -l2 --color=always'
 hg --config extensions.color= log -p -l2 --color=always
 
+echo '% log -r tip --stat'
+hg log -r tip --stat
+
 cd ..
 
 hg init usertest
--- a/tests/test-log.out	Fri Apr 30 17:41:09 2010 -0300
+++ b/tests/test-log.out	Sat May 01 15:14:22 2010 -0500
@@ -306,6 +306,16 @@
 @@ -0,0 +1,1 @@
 +b2
 
+% log -r tip --stat
+changeset:   6:2404bbcab562
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:01 1970 +0000
+summary:     b1.1
+
+ b1 |  1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
 adding a
 adding b
 changeset:   0:29a4c94f1924
--- a/tests/test-mq	Fri Apr 30 17:41:09 2010 -0300
+++ b/tests/test-mq	Sat May 01 15:14:22 2010 -0500
@@ -219,6 +219,19 @@
 hg qpop test2.patch-2
 hg qpush test1b.patch+1
 
+echo % qpush --move
+hg qpop -a
+hg qpush --move test2.patch # move to front
+hg qpush --move test1b.patch
+hg qpush --move test.patch # noop move
+hg qseries -v
+hg qpop -a
+hg qpush --move test.patch # cleaning up
+hg qpush --move test1b.patch
+hg qpush --move bogus # nonexistent patch
+hg qpush --move test.patch # already applied
+hg qpush
+
 echo % pop, qapplied, qunapplied
 hg qseries -v
 echo % qapplied -1 test.patch
--- a/tests/test-mq.out	Fri Apr 30 17:41:09 2010 -0300
+++ b/tests/test-mq.out	Sat May 01 15:14:22 2010 -0500
@@ -193,6 +193,32 @@
 applying test1b.patch
 applying test2.patch
 now at: test2.patch
+% qpush --move
+popping test2.patch
+popping test1b.patch
+popping test.patch
+patch queue now empty
+applying test2.patch
+now at: test2.patch
+applying test1b.patch
+now at: test1b.patch
+applying test.patch
+now at: test.patch
+0 A test2.patch
+1 A test1b.patch
+2 A test.patch
+popping test.patch
+popping test1b.patch
+popping test2.patch
+patch queue now empty
+applying test.patch
+now at: test.patch
+applying test1b.patch
+now at: test1b.patch
+abort: patch bogus not in series
+abort: cannot push to a previous patch: test.patch
+applying test2.patch
+now at: test2.patch
 % pop, qapplied, qunapplied
 0 A test.patch
 1 A test1b.patch
--- a/tests/test-tag	Fri Apr 30 17:41:09 2010 -0300
+++ b/tests/test-tag	Sat May 01 15:14:22 2010 -0500
@@ -68,3 +68,8 @@
 cat .hgtags
 hg tag -d '1000000 0' newline
 cat .hgtags
+
+echo % tag and branch using same name
+hg branch tag-and-branch-same-name
+hg ci -m"discouraged"
+hg tag tag-and-branch-same-name
--- a/tests/test-tag.out	Fri Apr 30 17:41:09 2010 -0300
+++ b/tests/test-tag.out	Sat May 01 15:14:22 2010 -0500
@@ -94,3 +94,6 @@
 f68b039e72eacbb2e68b0543e1f6e50990aa2bb5 localnewline
 0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar
 6ae703d793c8b1f097116869275ecd97b2977a2b newline
+% tag and branch using same name
+marked working directory as branch tag-and-branch-same-name
+warning: tag tag-and-branch-same-name conflicts with existing branch name