--- 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;35m@@ -0,0 +1,1 @@[0m
[0;32m+b2[0m
+% 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