merge.
--- a/.hgignore Thu Aug 10 16:59:58 2006 +0200
+++ b/.hgignore Tue Aug 22 07:55:10 2006 -0700
@@ -21,6 +21,7 @@
MANIFEST
patches
mercurial/__version__.py
+.DS_Store
syntax: regexp
^\.pc/
--- a/CONTRIBUTORS Thu Aug 10 16:59:58 2006 +0200
+++ b/CONTRIBUTORS Tue Aug 22 07:55:10 2006 -0700
@@ -4,6 +4,7 @@
Muli Ben-Yehuda <mulix at mulix.org>
Mikael Berthe <mikael at lilotux.net>
Benoit Boissinot <bboissin at gmail.com>
+Brendan Cully <brendan at kublai.com>
Vincent Danjean <vdanjean.ml at free.fr>
Jake Edge <jake at edge2.net>
Michael Fetterman <michael.fetterman at intel.com>
--- a/contrib/mercurial.el Thu Aug 10 16:59:58 2006 +0200
+++ b/contrib/mercurial.el Tue Aug 22 07:55:10 2006 -0700
@@ -722,7 +722,7 @@
(if (not hg-root-dir)
(error "error: %s: directory is not part of a Mercurial repository."
default-directory)
- (cd (hg-root))))))
+ (cd hg-root-dir)))))
(defun hg-add (path)
"Add PATH to the Mercurial repository on the next commit.
--- a/doc/hg.1.txt Thu Aug 10 16:59:58 2006 +0200
+++ b/doc/hg.1.txt Tue Aug 22 07:55:10 2006 -0700
@@ -216,6 +216,6 @@
COPYING
-------
-Copyright \(C) 2005 Matt Mackall.
+Copyright \(C) 2005, 2006 Matt Mackall.
Free use of this software is granted under the terms of the GNU General
Public License (GPL).
--- a/doc/hgmerge.1.txt Thu Aug 10 16:59:58 2006 +0200
+++ b/doc/hgmerge.1.txt Tue Aug 22 07:55:10 2006 -0700
@@ -30,6 +30,6 @@
COPYING
-------
-Copyright \(C) 2005 Matt Mackall.
+Copyright \(C) 2005, 2006 Matt Mackall.
Free use of this software is granted under the terms of the GNU General
Public License (GPL).
--- a/doc/hgrc.5.txt Thu Aug 10 16:59:58 2006 +0200
+++ b/doc/hgrc.5.txt Tue Aug 22 07:55:10 2006 -0700
@@ -306,7 +306,7 @@
smtp::
Configuration for extensions that need to send email messages.
host;;
- Optional. Host name of mail server. Default: "mail".
+ Host name of mail server, e.g. "mail.example.com".
port;;
Optional. Port to connect to on mail server. Default: 25.
tls;;
@@ -377,6 +377,9 @@
remote command to use for clone/push/pull operations. Default is 'hg'.
ssh;;
command to use for SSH connections. Default is 'ssh'.
+ strict;;
+ Require exact command names, instead of allowing unambiguous
+ abbreviations. True or False. Default is False.
timeout;;
The timeout used when a lock is held (in seconds), a negative value
means no timeout. Default is 600.
--- a/doc/ja/hg.1.ja.txt Thu Aug 10 16:59:58 2006 +0200
+++ b/doc/ja/hg.1.ja.txt Tue Aug 22 07:55:10 2006 -0700
@@ -862,6 +862,6 @@
著作権情報
-----
-Copyright (C) 2005 Matt Mackall.
+Copyright (C) 2005, 2006 Matt Mackall.
このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
認められます。
--- a/doc/ja/hgmerge.1.ja.txt Thu Aug 10 16:59:58 2006 +0200
+++ b/doc/ja/hgmerge.1.ja.txt Tue Aug 22 07:55:10 2006 -0700
@@ -32,6 +32,6 @@
著作権情報
----
-Copyright (C) 2005 Matt Mackall.
+Copyright (C) 2005, 2006 Matt Mackall.
このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
認められます。
--- a/hgext/extdiff.py Thu Aug 10 16:59:58 2006 +0200
+++ b/hgext/extdiff.py Tue Aug 22 07:55:10 2006 -0700
@@ -5,19 +5,24 @@
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
#
-# allow to use external programs to compare revisions, or revision
-# with working dir. program is called with two arguments: paths to
-# directories containing snapshots of files to compare.
+# The `extdiff' Mercurial extension allows you to use external programs
+# to compare revisions, or revision with working dir. The external diff
+# programs are called with a configurable set of options and two
+# non-option arguments: paths to directories containing snapshots of
+# files to compare.
#
-# to enable:
+# To enable this extension:
#
# [extensions]
# hgext.extdiff =
#
-# also allows to configure new diff commands, so you do not need to
-# type "hg extdiff -p kdiff3" always.
+# The `extdiff' extension also allows to configure new diff commands, so
+# you do not need to type "hg extdiff -p kdiff3" always.
#
# [extdiff]
+# # add new command that runs GNU diff(1) in 'context diff' mode
+# cmd.cdiff = gdiff
+# opts.cdiff = -Nprc5
# # add new command called vdiff, runs kdiff3
# cmd.vdiff = kdiff3
# # add new command called meld, runs meld (no need to name twice)
@@ -26,16 +31,23 @@
# #(see http://www.vim.org/scripts/script.php?script_id=102)
# cmd.vimdiff = LC_ALL=C gvim -f '+bdel 1 2' '+ execute "DirDiff ".argv(0)." ".argv(1)'
#
-# you can use -I/-X and list of file or directory names like normal
-# "hg diff" command. extdiff makes snapshots of only needed files, so
-# compare program will be fast.
+# Each custom diff commands can have two parts: a `cmd' and an `opts'
+# part. The cmd.xxx option defines the name of an executable program
+# that will be run, and opts.xxx defines a set of command-line options
+# which will be inserted to the command between the program name and
+# the files/directories to diff (i.e. the cdiff example above).
+#
+# You can use -I/-X and list of file or directory names like normal
+# "hg diff" command. The `extdiff' extension makes snapshots of only
+# needed files, so running the external diff program will actually be
+# pretty fast (at least faster than having to compare the entire tree).
from mercurial.demandload import demandload
from mercurial.i18n import gettext as _
from mercurial.node import *
-demandload(globals(), 'mercurial:commands,util os shutil tempfile')
+demandload(globals(), 'mercurial:commands,cmdutil,util os shutil tempfile')
-def dodiff(ui, repo, diffcmd, pats, opts):
+def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
def snapshot_node(files, node):
'''snapshot files as of some revision'''
changes = repo.changelog.read(node)
@@ -79,9 +91,9 @@
return dirname
node1, node2 = commands.revpair(ui, repo, opts['rev'])
- files, matchfn, anypats = commands.matchpats(repo, pats, opts)
- modified, added, removed, deleted, unknown = repo.changes(
- node1, node2, files, match=matchfn)
+ files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
+ modified, added, removed, deleted, unknown = repo.status(
+ node1, node2, files, match=matchfn)[:5]
if not (modified or added or removed):
return 0
@@ -92,9 +104,12 @@
dir2 = snapshot_node(modified + added, node2)
else:
dir2 = snapshot_wdir(modified + added)
- util.system('%s %s "%s" "%s"' %
- (diffcmd, ' '.join(opts['option']), dir1, dir2),
- cwd=tmproot)
+ cmdline = ('%s %s %s %s' %
+ (util.shellquote(diffcmd),
+ ' '.join(map(util.shellquote, diffopts)),
+ util.shellquote(dir1), util.shellquote(dir2)))
+ ui.debug('running %r in %s\n' % (cmdline, tmproot))
+ util.system(cmdline, cwd=tmproot)
return 1
finally:
ui.note(_('cleaning up temp directory\n'))
@@ -104,7 +119,9 @@
'''use external program to diff repository (or selected files)
Show differences between revisions for the specified files, using
- an external program. The default program used is "diff -Npru".
+ an external program. The default program used is diff, with
+ default options "-Npru".
+
To select a different program, use the -p option. The program
will be passed the names of two directories to compare. To pass
additional options to the program, use the -o option. These will
@@ -115,7 +132,8 @@
specified then that revision is compared to the working
directory, and, when no revisions are specified, the
working directory files are compared to its parent.'''
- return dodiff(ui, repo, opts['program'] or 'diff -Npru', pats, opts)
+ return dodiff(ui, repo, opts['program'] or 'diff',
+ opts['option'] or ['-Npru'], pats, opts)
cmdtable = {
"extdiff":
@@ -133,21 +151,25 @@
if not cmd.startswith('cmd.'): continue
cmd = cmd[4:]
if not path: path = cmd
- def save(cmd, path):
+ diffopts = ui.config('extdiff', 'opts.' + cmd, '')
+ diffopts = diffopts and [diffopts] or []
+ def save(cmd, path, diffopts):
'''use closure to save diff command to use'''
def mydiff(ui, repo, *pats, **opts):
- return dodiff(ui, repo, path, pats, opts)
- mydiff.__doc__ = '''use %s to diff repository (or selected files)
+ return dodiff(ui, repo, path, diffopts, pats, opts)
+ mydiff.__doc__ = '''use %(path)r to diff repository (or selected files)
Show differences between revisions for the specified
- files, using the %s program.
+ files, using the %(path)r program.
When two revision arguments are given, then changes are
shown between those revisions. If only one revision is
specified then that revision is compared to the working
directory, and, when no revisions are specified, the
- working directory files are compared to its parent.''' % (cmd, cmd)
+ working directory files are compared to its parent.''' % {
+ 'path': path,
+ }
return mydiff
- cmdtable[cmd] = (save(cmd, path),
+ cmdtable[cmd] = (save(cmd, path, diffopts),
cmdtable['extdiff'][1][1:],
_('hg %s [OPT]... [FILE]...') % cmd)
--- a/hgext/fetch.py Thu Aug 10 16:59:58 2006 +0200
+++ b/hgext/fetch.py Tue Aug 22 07:55:10 2006 -0700
@@ -24,13 +24,13 @@
if modheads == 0:
return 0
if modheads == 1:
- return hg.update(repo, repo.changelog.tip(), wlock=wlock)
+ return hg.clean(repo, repo.changelog.tip(), wlock=wlock)
newheads = repo.heads(parent)
newchildren = [n for n in repo.heads(parent) if n != parent]
newparent = parent
if newchildren:
newparent = newchildren[0]
- hg.update(repo, newparent, wlock=wlock)
+ hg.clean(repo, newparent, wlock=wlock)
newheads = [n for n in repo.heads() if n != newparent]
err = False
if newheads:
--- a/hgext/gpg.py Thu Aug 10 16:59:58 2006 +0200
+++ b/hgext/gpg.py Tue Aug 22 07:55:10 2006 -0700
@@ -221,7 +221,7 @@
repo.opener("localsigs", "ab").write(sigmessage)
return
- for x in repo.changes():
+ for x in repo.status()[:5]:
if ".hgsigs" in x and not opts["force"]:
raise util.Abort(_("working copy of .hgsigs is changed "
"(please commit .hgsigs manually "
--- a/hgext/hbisect.py Thu Aug 10 16:59:58 2006 +0200
+++ b/hgext/hbisect.py Tue Aug 22 07:55:10 2006 -0700
@@ -23,10 +23,10 @@
return parents.pop()
def check_clean(ui, repo):
- modified, added, removed, deleted, unknown = repo.changes()
- if modified or added or removed:
- ui.warn("Repository is not clean, please commit or revert\n")
- sys.exit(1)
+ modified, added, removed, deleted, unknown = repo.status()[:5]
+ if modified or added or removed:
+ ui.warn("Repository is not clean, please commit or revert\n")
+ sys.exit(1)
class bisect(object):
"""dichotomic search in the DAG of changesets"""
--- a/hgext/hgk.py Thu Aug 10 16:59:58 2006 +0200
+++ b/hgext/hgk.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,12 +1,13 @@
# Minimal support for git commands on an hg repository
#
-# Copyright 2005 Chris Mason <mason@suse.com>
+# Copyright 2005, 2006 Chris Mason <mason@suse.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
-import time, sys, signal, os
-from mercurial import hg, mdiff, fancyopts, commands, ui, util
+from mercurial.demandload import *
+demandload(globals(), 'time sys signal os')
+demandload(globals(), 'mercurial:hg,mdiff,fancyopts,commands,ui,util')
def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
changes=None, text=False):
@@ -14,7 +15,7 @@
return time.asctime(time.gmtime(c[2][0]))
if not changes:
- changes = repo.changes(node1, node2, files, match=match)
+ changes = repo.status(node1, node2, files, match=match)[:5]
modified, added, removed, deleted, unknown = changes
if files:
modified, added, removed = map(lambda x: filterfiles(files, x),
@@ -67,12 +68,12 @@
if node2:
change = repo.changelog.read(node2)
mmap2 = repo.manifest.read(change[0])
- modified, added, removed, deleted, unknown = repo.changes(node1, node2)
+ modified, added, removed, deleted, unknown = repo.status(node1, node2)[:5]
def read(f): return repo.file(f).read(mmap2[f])
date2 = date(change)
else:
date2 = time.asctime()
- modified, added, removed, deleted, unknown = repo.changes(node1)
+ modified, added, removed, deleted, unknown = repo.status(node1)[:5]
if not node1:
node1 = repo.dirstate.parents()[0]
def read(f): return file(os.path.join(repo.root, f)).read()
--- a/hgext/mq.py Thu Aug 10 16:59:58 2006 +0200
+++ b/hgext/mq.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,7 +1,6 @@
-
# queue.py - patch queues for mercurial
#
-# Copyright 2005 Chris Mason <mason@suse.com>
+# Copyright 2005, 2006 Chris Mason <mason@suse.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
@@ -31,9 +30,10 @@
'''
from mercurial.demandload import *
+from mercurial.i18n import gettext as _
+from mercurial import commands
demandload(globals(), "os sys re struct traceback errno bz2")
-from mercurial.i18n import gettext as _
-from mercurial import ui, hg, revlog, commands, util
+demandload(globals(), "mercurial:cmdutil,hg,patch,revlog,ui,util")
commands.norepo += " qclone qversion"
@@ -66,6 +66,7 @@
self.guards_path = "guards"
self.active_guards = None
self.guards_dirty = False
+ self._diffopts = None
if os.path.exists(self.join(self.series_path)):
self.full_series = self.opener(self.series_path).read().splitlines()
@@ -75,6 +76,11 @@
lines = self.opener(self.status_path).read().splitlines()
self.applied = [statusentry(l) for l in lines]
+ def diffopts(self):
+ if self._diffopts is None:
+ self._diffopts = patch.diffopts(self.ui)
+ return self._diffopts
+
def join(self, *p):
return os.path.join(self.path, *p)
@@ -176,11 +182,11 @@
if exactneg:
return False, exactneg[0]
pos = [g for g in patchguards if g[0] == '+']
- nonpos = [g for g in pos if g[1:] not in guards]
+ exactpos = [g for g in pos if g[1:] in guards]
if pos:
- if not nonpos:
- return True, ''
- return False, nonpos
+ if exactpos:
+ return True, exactpos[0]
+ return False, pos
return True, ''
def explain_pushable(self, idx, all_patches=False):
@@ -247,6 +253,9 @@
for line in file(pf):
line = line.rstrip()
+ if line.startswith('diff --git'):
+ diffstart = 2
+ break
if diffstart:
if line.startswith('+++ '):
diffstart = 2
@@ -292,6 +301,13 @@
message.insert(0, subject)
return (message, comments, user, date, diffstart > 1)
+ def printdiff(self, repo, node1, node2=None, files=None,
+ fp=None, changes=None, opts={}):
+ fns, matchfn, anypats = cmdutil.matchpats(repo, files, opts)
+
+ patch.diff(repo, node1, node2, fns, match=matchfn,
+ fp=fp, changes=changes, opts=self.diffopts())
+
def mergeone(self, repo, mergeq, head, patch, rev, wlock):
# first try just applying the patch
(err, n) = self.apply(repo, [ patch ], update_status=False,
@@ -325,7 +341,7 @@
if comments:
comments = "\n".join(comments) + '\n\n'
patchf.write(comments)
- commands.dodiff(patchf, self.ui, repo, head, n)
+ self.printdiff(repo, head, n, fp=patchf)
patchf.close()
return (0, n)
@@ -390,39 +406,15 @@
'''Apply patchfile to the working directory.
patchfile: file name of patch'''
try:
- pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
- f = os.popen("%s -d %s -p1 --no-backup-if-mismatch < %s" %
- (pp, util.shellquote(repo.root), util.shellquote(patchfile)))
- except:
- self.ui.warn("patch failed, unable to continue (try -v)\n")
- return (None, [], False)
- files = []
- fuzz = False
- for l in f:
- l = l.rstrip('\r\n');
- if self.ui.verbose:
- self.ui.warn(l + "\n")
- if l[:14] == 'patching file ':
- pf = os.path.normpath(util.parse_patch_output(l))
- if pf not in files:
- files.append(pf)
- printed_file = False
- file_str = l
- elif l.find('with fuzz') >= 0:
- if not printed_file:
- self.ui.warn(file_str + '\n')
- printed_file = True
- self.ui.warn(l + '\n')
- fuzz = True
- elif l.find('saving rejects to file') >= 0:
- self.ui.warn(l + '\n')
- elif l.find('FAILED') >= 0:
- if not printed_file:
- self.ui.warn(file_str + '\n')
- printed_file = True
- self.ui.warn(l + '\n')
+ (files, fuzz) = patch.patch(patchfile, self.ui, strip=1,
+ cwd=repo.root)
+ except Exception, inst:
+ self.ui.note(str(inst) + '\n')
+ if not self.ui.verbose:
+ self.ui.warn("patch failed, unable to continue (try -v)\n")
+ return (False, [], False)
- return (not f.close(), files, fuzz)
+ return (True, files, fuzz)
def apply(self, repo, series, list=False, update_status=True,
strict=False, patchdir=None, merge=None, wlock=None):
@@ -435,43 +427,37 @@
lock = repo.lock()
tr = repo.transaction()
n = None
- for patch in series:
- pushable, reason = self.pushable(patch)
+ for patchname in series:
+ pushable, reason = self.pushable(patchname)
if not pushable:
- self.explain_pushable(patch, all_patches=True)
+ self.explain_pushable(patchname, all_patches=True)
continue
- self.ui.warn("applying %s\n" % patch)
- pf = os.path.join(patchdir, patch)
+ self.ui.warn("applying %s\n" % patchname)
+ pf = os.path.join(patchdir, patchname)
try:
- message, comments, user, date, patchfound = self.readheaders(patch)
+ message, comments, user, date, patchfound = self.readheaders(patchname)
except:
- self.ui.warn("Unable to read %s\n" % pf)
+ self.ui.warn("Unable to read %s\n" % patchname)
err = 1
break
if not message:
- message = "imported patch %s\n" % patch
+ message = "imported patch %s\n" % patchname
else:
if list:
- message.append("\nimported patch %s" % patch)
+ message.append("\nimported patch %s" % patchname)
message = '\n'.join(message)
(patcherr, files, fuzz) = self.patch(repo, pf)
patcherr = not patcherr
- if merge and len(files) > 0:
+ if merge and files:
# Mark as merged and update dirstate parent info
- repo.dirstate.update(repo.dirstate.filterfiles(files), 'm')
+ repo.dirstate.update(repo.dirstate.filterfiles(files.keys()), 'm')
p1, p2 = repo.dirstate.parents()
repo.dirstate.setparents(p1, merge)
- if len(files) > 0:
- cwd = repo.getcwd()
- cfiles = files
- if cwd:
- cfiles = [util.pathto(cwd, f) for f in files]
- commands.addremove_lock(self.ui, repo, cfiles,
- opts={}, wlock=wlock)
+ files = patch.updatedir(self.ui, repo, files, wlock=wlock)
n = repo.commit(files, message, user, date, force=1, lock=lock,
wlock=wlock)
@@ -479,11 +465,11 @@
raise util.Abort(_("repo commit failed"))
if update_status:
- self.applied.append(statusentry(revlog.hex(n), patch))
+ self.applied.append(statusentry(revlog.hex(n), patchname))
if patcherr:
if not patchfound:
- self.ui.warn("patch %s is empty\n" % patch)
+ self.ui.warn("patch %s is empty\n" % patchname)
err = 0
else:
self.ui.warn("patch failed, rejects left in working dir\n")
@@ -497,21 +483,28 @@
tr.close()
return (err, n)
- def delete(self, repo, patch, force=False):
- patch = self.lookup(patch, strict=True)
- info = self.isapplied(patch)
- if info:
- raise util.Abort(_("cannot delete applied patch %s") % patch)
- if patch not in self.series:
- raise util.Abort(_("patch %s not in series file") % patch)
- if force:
+ def delete(self, repo, patches, keep=False):
+ realpatches = []
+ for patch in patches:
+ patch = self.lookup(patch, strict=True)
+ info = self.isapplied(patch)
+ if info:
+ raise util.Abort(_("cannot delete applied patch %s") % patch)
+ if patch not in self.series:
+ raise util.Abort(_("patch %s not in series file") % patch)
+ realpatches.append(patch)
+
+ if not keep:
r = self.qrepo()
if r:
- r.remove([patch], True)
+ r.remove(realpatches, True)
else:
os.unlink(self.join(patch))
- i = self.find_series(patch)
- del self.full_series[i]
+
+ indices = [self.find_series(p) for p in realpatches]
+ indices.sort()
+ for i in indices[-1::-1]:
+ del self.full_series[i]
self.parse_series()
self.series_dirty = 1
@@ -523,19 +516,20 @@
raise util.Abort(_("queue top not at same revision as working directory"))
return top
return None
- def check_localchanges(self, repo):
- (c, a, r, d, u) = repo.changes(None, None)
- if c or a or d or r:
- raise util.Abort(_("local changes found, refresh first"))
+ def check_localchanges(self, repo, force=False, refresh=True):
+ m, a, r, d = repo.status()[:4]
+ if m or a or r or d:
+ if not force:
+ if refresh:
+ raise util.Abort(_("local changes found, refresh first"))
+ else:
+ raise util.Abort(_("local changes found"))
+ return m, a, r, d
def new(self, repo, patch, msg=None, force=None):
if os.path.exists(self.join(patch)):
raise util.Abort(_('patch "%s" already exists') % patch)
- commitfiles = []
- (c, a, r, d, u) = repo.changes(None, None)
- if c or a or d or r:
- if not force:
- raise util.Abort(_("local changes found, refresh first"))
- commitfiles = c + a + r
+ m, a, r, d = self.check_localchanges(repo, force)
+ commitfiles = m + a + r
self.check_toppatch(repo)
wlock = repo.wlock()
insert = self.full_series_end()
@@ -561,7 +555,7 @@
r = self.qrepo()
if r: r.add([patch])
if commitfiles:
- self.refresh(repo, msg=None, short=True)
+ self.refresh(repo, short=True)
def strip(self, repo, rev, update=True, backup="all", wlock=None):
def limitheads(chlog, stop):
@@ -649,9 +643,7 @@
revnum = chlog.rev(rev)
if update:
- (c, a, r, d, u) = repo.changes(None, None)
- if c or a or d or r:
- raise util.Abort(_("local changes found"))
+ self.check_localchanges(repo, refresh=False)
urev = self.qparents(repo, rev)
hg.clean(repo, urev, wlock=wlock)
repo.dirstate.write()
@@ -725,6 +717,8 @@
# 2) a unique substring of the patch name was given
# 3) patchname[-+]num to indicate an offset in the series file
def lookup(self, patch, strict=False):
+ patch = patch and str(patch)
+
def partial_name(s):
if s in self.series:
return s
@@ -886,17 +880,16 @@
top = self.check_toppatch(repo)
qp = self.qparents(repo, rev)
changes = repo.changelog.read(qp)
- mf1 = repo.manifest.readflags(changes[0])
mmap = repo.manifest.read(changes[0])
- (c, a, r, d, u) = repo.changes(qp, top)
+ m, a, r, d, u = repo.status(qp, top)[:5]
if d:
raise util.Abort("deletions found between repo revs")
- for f in c:
+ for f in m:
getfile(f, mmap[f])
for f in r:
getfile(f, mmap[f])
- util.set_exec(repo.wjoin(f), mf1[f])
- repo.dirstate.update(c + r, 'n')
+ util.set_exec(repo.wjoin(f), mmap.execf(f))
+ repo.dirstate.update(m + r, 'n')
for f in a:
try: os.unlink(repo.wjoin(f))
except: raise
@@ -912,15 +905,15 @@
else:
self.ui.write("Patch queue now empty\n")
- def diff(self, repo, files):
+ def diff(self, repo, pats, opts):
top = self.check_toppatch(repo)
if not top:
self.ui.write("No patches applied\n")
return
qp = self.qparents(repo, top)
- commands.dodiff(sys.stdout, self.ui, repo, qp, None, files)
+ self.printdiff(repo, qp, files=pats, opts=opts)
- def refresh(self, repo, msg=None, short=False):
+ def refresh(self, repo, pats=None, **opts):
if len(self.applied) == 0:
self.ui.write("No patches applied\n")
return
@@ -933,7 +926,7 @@
message, comments, user, date, patchfound = self.readheaders(patch)
patchf = self.opener(patch, "w")
- msg = msg.rstrip()
+ msg = opts.get('msg', '').rstrip()
if msg:
if comments:
# Remove existing message.
@@ -947,6 +940,7 @@
comments = "\n".join(comments) + '\n\n'
patchf.write(comments)
+ fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
tip = repo.changelog.tip()
if top == tip:
# if the top of our patch queue is also the tip, there is an
@@ -959,30 +953,30 @@
# patch already
#
# this should really read:
- #(cc, dd, aa, aa2, uu) = repo.changes(tip, patchparent)
+ # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
# but we do it backwards to take advantage of manifest/chlog
- # caching against the next repo.changes call
+ # caching against the next repo.status call
#
- (cc, aa, dd, aa2, uu) = repo.changes(patchparent, tip)
- if short:
- filelist = cc + aa + dd
+ mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
+ if opts.get('short'):
+ filelist = mm + aa + dd
else:
filelist = None
- (c, a, r, d, u) = repo.changes(None, None, filelist)
+ m, a, r, d, u = repo.status(files=filelist)[:5]
# we might end up with files that were added between tip and
# the dirstate parent, but then changed in the local dirstate.
# in this case, we want them to only show up in the added section
- for x in c:
+ for x in m:
if x not in aa:
- cc.append(x)
+ mm.append(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)]
- cc.append(x)
+ mm.append(x)
else:
aa.append(x)
# make sure any files deleted in the local dirstate
@@ -993,23 +987,34 @@
del aa[aa.index(x)]
forget.append(x)
continue
- elif x in cc:
- del cc[cc.index(x)]
+ elif x in mm:
+ del mm[mm.index(x)]
dd.append(x)
- c = list(util.unique(cc))
+ m = list(util.unique(mm))
r = list(util.unique(dd))
a = list(util.unique(aa))
- filelist = list(util.unique(c + r + a ))
- commands.dodiff(patchf, self.ui, repo, patchparent, None,
- filelist, changes=(c, a, r, [], u))
+ filelist = filter(matchfn, util.unique(m + r + a))
+ self.printdiff(repo, patchparent, files=filelist,
+ changes=(m, a, r, [], u), fp=patchf)
patchf.close()
changes = repo.changelog.read(tip)
repo.dirstate.setparents(*cparents)
+ copies = [(f, repo.dirstate.copied(f)) for f in a]
repo.dirstate.update(a, 'a')
+ for dst, src in copies:
+ repo.dirstate.copy(src, dst)
repo.dirstate.update(r, 'r')
- repo.dirstate.update(c, 'n')
+ # if the patch excludes a modified file, mark that file with mtime=0
+ # so status can see it.
+ mm = []
+ for i in range(len(m)-1, -1, -1):
+ if not matchfn(m[i]):
+ mm.append(m[i])
+ del m[i]
+ repo.dirstate.update(m, 'n')
+ repo.dirstate.update(mm, 'n', st_mtime=0)
repo.dirstate.forget(forget)
if not msg:
@@ -1025,7 +1030,7 @@
self.applied[-1] = statusentry(revlog.hex(n), patch)
self.applied_dirty = 1
else:
- commands.dodiff(patchf, self.ui, repo, patchparent, None)
+ self.printdiff(repo, patchparent, fp=patchf)
patchf.close()
self.pop(repo, force=True, wlock=wlock)
self.push(repo, force=True, wlock=wlock)
@@ -1224,7 +1229,7 @@
if not self.ui.verbose:
p = pname
else:
- p = str(self.series.index(pname)) + " " + p
+ p = str(self.series.index(pname)) + " " + pname
return p
def top(self, repo):
@@ -1291,13 +1296,13 @@
if qrepo:
qrepo.add(added)
-def delete(ui, repo, patch, **opts):
- """remove a patch from the series file
+def delete(ui, repo, patch, *patches, **opts):
+ """remove patches from queue
- The patch must not be applied.
- With -f, deletes the patch file as well as the series entry."""
+ The patches must not be applied.
+ With -k, the patch files are preserved in the patch directory."""
q = repo.mq
- q.delete(repo, patch, force=opts.get('force'))
+ q.delete(repo, (patch,) + patches, keep=opts.get('keep'))
q.save_dirty()
return 0
@@ -1419,17 +1424,24 @@
changes unless -f is specified, in which case the patch will
be initialised with them.
- -m or -l set the patch header as well as the commit message.
- If neither is specified, the patch header is empty and the
+ -e, -m or -l set the patch header as well as the commit message.
+ If none is specified, the patch header is empty and the
commit message is 'New patch: PATCH'"""
q = repo.mq
message = commands.logmessage(opts)
+ if opts['edit']:
+ message = ui.edit(message, ui.username())
q.new(repo, patch, msg=message, force=opts['force'])
q.save_dirty()
return 0
-def refresh(ui, repo, **opts):
- """update the current patch"""
+def refresh(ui, repo, *pats, **opts):
+ """update the current patch
+
+ If any file patterns are provided, the refreshed patch will contain only
+ the modifications that match those patterns; the remaining modifications
+ will remain in the working directory.
+ """
q = repo.mq
message = commands.logmessage(opts)
if opts['edit']:
@@ -1438,14 +1450,13 @@
patch = q.applied[-1].name
(message, comment, user, date, hasdiff) = q.readheaders(patch)
message = ui.edit('\n'.join(message), user or ui.username())
- q.refresh(repo, msg=message, short=opts['short'])
+ q.refresh(repo, pats, msg=message, **opts)
q.save_dirty()
return 0
-def diff(ui, repo, *files, **opts):
+def diff(ui, repo, *pats, **opts):
"""diff of the current patch"""
- # deep in the dirstate code, the walkhelper method wants a list, not a tuple
- repo.mq.diff(repo, list(files))
+ repo.mq.diff(repo, pats, opts)
return 0
def fold(ui, repo, *files, **opts):
@@ -1455,7 +1466,7 @@
applied to the current patch in the order given. If all the
patches apply successfully, the current patch will be refreshed
with the new cumulative patch, and the folded patches will
- be deleted. With -f/--force, the folded patch files will
+ be deleted. With -k/--keep, the folded patch files will not
be removed afterwards.
The header for each folded patch will be concatenated with
@@ -1477,20 +1488,21 @@
patches = []
messages = []
for f in files:
- patch = q.lookup(f)
- if patch in patches or patch == parent:
- ui.warn(_('Skipping already folded patch %s') % patch)
- if q.isapplied(patch):
- raise util.Abort(_('qfold cannot fold already applied patch %s') % patch)
- patches.append(patch)
+ p = q.lookup(f)
+ if p in patches or p == parent:
+ ui.warn(_('Skipping already folded patch %s') % p)
+ if q.isapplied(p):
+ raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
+ patches.append(p)
- for patch in patches:
+ for p in patches:
if not message:
- messages.append(q.readheaders(patch)[0])
- pf = q.join(patch)
+ messages.append(q.readheaders(p)[0])
+ pf = q.join(p)
(patchsuccess, files, fuzz) = q.patch(repo, pf)
if not patchsuccess:
- raise util.Abort(_('Error folding patch %s') % patch)
+ raise util.Abort(_('Error folding patch %s') % p)
+ patch.updatedir(ui, repo, files)
if not message:
message, comments, user = q.readheaders(parent)[0:3]
@@ -1503,29 +1515,26 @@
message = ui.edit(message, user or ui.username())
q.refresh(repo, msg=message)
-
- for patch in patches:
- q.delete(repo, patch, force=opts['force'])
-
+ q.delete(repo, patches, keep=opts['keep'])
q.save_dirty()
def guard(ui, repo, *args, **opts):
'''set or print guards for a patch
- guards control whether a patch can be pushed. a patch with no
- guards is aways pushed. a patch with posative guard ("+foo") is
- pushed only if qselect command enables guard "foo". a patch with
- nagative guard ("-foo") is never pushed if qselect command enables
- guard "foo".
+ Guards control whether a patch can be pushed. A patch with no
+ guards is always pushed. A patch with a positive guard ("+foo") is
+ pushed only if the qselect command has activated it. A patch with
+ a negative guard ("-foo") is never pushed if the qselect command
+ has activated it.
- with no arguments, default is to print current active guards.
- with arguments, set active guards for patch.
+ With no arguments, print the currently active guards.
+ With arguments, set guards for the named patch.
- to set nagative guard "-foo" on topmost patch ("--" is needed so
- hg will not interpret "-foo" as argument):
+ To set a negative guard "-foo" on topmost patch ("--" is needed so
+ hg will not interpret "-foo" as an option):
hg qguard -- -foo
- to set guards on other patch:
+ To set guards on another patch:
hg qguard other.patch +2.6.17 -stable
'''
def status(idx):
@@ -1731,38 +1740,57 @@
def select(ui, repo, *args, **opts):
'''set or print guarded patches to push
- use qguard command to set or print guards on patch. then use
- qselect to tell mq which guards to use. example:
+ Use the qguard command to set or print guards on patch, then use
+ qselect to tell mq which guards to use. A patch will be pushed if it
+ has no guards or any positive guards match the currently selected guard,
+ but will not be pushed if any negative guards match the current guard.
+ For example:
- qguard foo.patch -stable (nagative guard)
- qguard bar.patch +stable (posative guard)
+ qguard foo.patch -stable (negative guard)
+ qguard bar.patch +stable (positive guard)
qselect stable
- this sets "stable" guard. mq will skip foo.patch (because it has
- nagative match) but push bar.patch (because it has posative
- match). patch is pushed only if all posative guards match and no
- nagative guards match.
+ This activates the "stable" guard. mq will skip foo.patch (because
+ it has a negative match) but push bar.patch (because it
+ has a positive match).
- with no arguments, default is to print current active guards.
- with arguments, set active guards as given.
+ With no arguments, prints the currently active guards.
+ With one argument, sets the active guard.
- use -n/--none to deactivate guards (no other arguments needed).
- when no guards active, patches with posative guards are skipped,
- patches with nagative guards are pushed.
+ Use -n/--none to deactivate guards (no other arguments needed).
+ When no guards are active, patches with positive guards are skipped
+ and patches with negative guards are pushed.
- use -s/--series to print list of all guards in series file (no
- other arguments needed). use -v for more information.'''
+ qselect can change the guards on applied patches. It does not pop
+ guarded patches by default. Use --pop to pop back to the last applied
+ patch that is not guarded. Use --reapply (which implies --pop) to push
+ back to the current patch afterwards, but skip guarded patches.
+
+ Use -s/--series to print a list of all guards in the series file (no
+ other arguments needed). Use -v for more information.'''
q = repo.mq
guards = q.active()
if args or opts['none']:
+ old_unapplied = q.unapplied(repo)
+ old_guarded = [i for i in xrange(len(q.applied)) if
+ not q.pushable(i)[0]]
q.set_active(args)
q.save_dirty()
if not args:
ui.status(_('guards deactivated\n'))
- if q.series:
- ui.status(_('%d of %d unapplied patches active\n') %
- (len(q.unapplied(repo)), len(q.series)))
+ if not opts['pop'] and not opts['reapply']:
+ unapplied = q.unapplied(repo)
+ guarded = [i for i in xrange(len(q.applied))
+ if not q.pushable(i)[0]]
+ if len(unapplied) != len(old_unapplied):
+ ui.status(_('number of unguarded, unapplied patches has '
+ 'changed from %d to %d\n') %
+ (len(old_unapplied), len(unapplied)))
+ if len(guarded) != len(old_guarded):
+ ui.status(_('number of guarded, applied patches has changed '
+ 'from %d to %d\n') %
+ (len(old_guarded), len(guarded)))
elif opts['series']:
guards = {}
noguards = 0
@@ -1790,9 +1818,51 @@
ui.write(g, '\n')
else:
ui.write(_('no active guards\n'))
+ reapply = opts['reapply'] and q.applied and q.appliedname(-1)
+ popped = False
+ if opts['pop'] or opts['reapply']:
+ for i in xrange(len(q.applied)):
+ pushable, reason = q.pushable(i)
+ if not pushable:
+ ui.status(_('popping guarded patches\n'))
+ popped = True
+ if i == 0:
+ q.pop(repo, all=True)
+ else:
+ q.pop(repo, i-1)
+ break
+ if popped:
+ try:
+ if reapply:
+ ui.status(_('reapplying unguarded patches\n'))
+ q.push(repo, reapply)
+ finally:
+ q.save_dirty()
def reposetup(ui, repo):
class mqrepo(repo.__class__):
+ def abort_if_wdir_patched(self, errmsg, force=False):
+ if self.mq.applied and not force:
+ parent = revlog.hex(self.dirstate.parents()[0])
+ if parent in [s.rev for s in self.mq.applied]:
+ raise util.Abort(errmsg)
+
+ def commit(self, *args, **opts):
+ if len(args) >= 6:
+ force = args[5]
+ else:
+ force = opts.get('force')
+ self.abort_if_wdir_patched(
+ _('cannot commit over an applied mq patch'),
+ force)
+
+ return super(mqrepo, self).commit(*args, **opts)
+
+ def push(self, remote, force=False, revs=None):
+ if self.mq.applied and not force:
+ raise util.Abort(_('source has mq patches applied'))
+ return super(mqrepo, self).push(remote, force, revs)
+
def tags(self):
if self.tagscache:
return self.tagscache
@@ -1814,8 +1884,9 @@
return tagscache
- repo.__class__ = mqrepo
- repo.mq = queue(ui, repo.join(""))
+ if repo.local():
+ repo.__class__ = mqrepo
+ repo.mq = queue(ui, repo.join(""))
cmdtable = {
"qapplied": (applied, [], 'hg qapplied [PATCH]'),
@@ -1833,15 +1904,18 @@
(commit,
commands.table["^commit|ci"][1],
'hg qcommit [OPTION]... [FILE]...'),
- "^qdiff": (diff, [], 'hg qdiff [FILE]...'),
- "qdelete":
+ "^qdiff": (diff,
+ [('I', 'include', [], _('include names matching the given patterns')),
+ ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+ 'hg qdiff [-I] [-X] [FILE]...'),
+ "qdelete|qremove|qrm":
(delete,
- [('f', 'force', None, _('delete patch file'))],
- 'hg qdelete [-f] PATCH'),
+ [('k', 'keep', None, _('keep patch file'))],
+ 'hg qdelete [-k] PATCH'),
'qfold':
(fold,
[('e', 'edit', None, _('edit patch header')),
- ('f', 'force', None, _('delete folded patch files')),
+ ('k', 'keep', None, _('keep folded patch files')),
('m', 'message', '', _('set patch header to <text>')),
('l', 'logfile', '', _('set patch header to contents of <file>'))],
'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
@@ -1862,10 +1936,11 @@
'hg qinit [-c]'),
"qnew":
(new,
- [('m', 'message', '', _('use <text> as commit message')),
+ [('e', 'edit', None, _('edit commit message')),
+ ('m', 'message', '', _('use <text> as commit message')),
('l', 'logfile', '', _('read the commit message from <file>')),
('f', 'force', None, _('import uncommitted changes into patch'))],
- 'hg qnew [-m TEXT] [-l FILE] [-f] PATCH'),
+ 'hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH'),
"qnext": (next, [], 'hg qnext'),
"qprev": (prev, [], 'hg qprev'),
"^qpop":
@@ -1887,8 +1962,10 @@
[('e', 'edit', None, _('edit commit message')),
('m', 'message', '', _('change commit message with <text>')),
('l', 'logfile', '', _('change commit message with <file> content')),
- ('s', 'short', None, 'short refresh')],
- 'hg qrefresh [-e] [-m TEXT] [-l FILE] [-s]'),
+ ('s', 'short', None, 'short refresh'),
+ ('I', 'include', [], _('include names matching the given patterns')),
+ ('X', 'exclude', [], _('exclude names matching the given patterns'))],
+ 'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] FILES...'),
'qrename|qmv':
(rename, [], 'hg qrename PATCH1 [PATCH2]'),
"qrestore":
@@ -1907,8 +1984,11 @@
'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
"qselect": (select,
[('n', 'none', None, _('disable all guards')),
- ('s', 'series', None, _('list all guards in series file'))],
- 'hg qselect [GUARDS]'),
+ ('s', 'series', None, _('list all guards in series file')),
+ ('', 'pop', None,
+ _('pop to before first guarded applied patch')),
+ ('', 'reapply', None, _('pop, then reapply patches'))],
+ 'hg qselect [OPTION...] [GUARD...]'),
"qseries":
(series,
[('m', 'missing', None, 'print patches not in series'),
@@ -1923,4 +2003,3 @@
"qtop": (top, [], 'hg qtop'),
"qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
}
-
--- a/hgext/notify.py Thu Aug 10 16:59:58 2006 +0200
+++ b/hgext/notify.py Tue Aug 22 07:55:10 2006 -0700
@@ -67,8 +67,8 @@
from mercurial.demandload import *
from mercurial.i18n import gettext as _
from mercurial.node import *
-demandload(globals(), 'email.Parser mercurial:commands,templater,util')
-demandload(globals(), 'fnmatch socket time')
+demandload(globals(), 'mercurial:commands,patch,templater,util,mail')
+demandload(globals(), 'email.Parser fnmatch socket time')
# template for single changeset can include email headers.
single_template = '''
@@ -229,8 +229,8 @@
else:
self.ui.status(_('notify: sending %d subscribers %d changes\n') %
(len(self.subs), count))
- mail = self.ui.sendmail()
- mail.sendmail(templater.email(msg['From']), self.subs, msgtext)
+ mail.sendmail(self.ui, templater.email(msg['From']),
+ self.subs, msgtext)
def diff(self, node, ref):
maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
@@ -238,7 +238,7 @@
return
fp = templater.stringio()
prev = self.repo.changelog.parents(node)[0]
- commands.dodiff(fp, self.ui, self.repo, prev, ref)
+ patch.diff(self.repo, fp, prev, ref)
difflines = fp.getvalue().splitlines(1)
if maxdiff > 0 and len(difflines) > maxdiff:
self.sio.write(_('\ndiffs (truncated from %d to %d lines):\n\n') %
--- a/hgext/patchbomb.py Thu Aug 10 16:59:58 2006 +0200
+++ b/hgext/patchbomb.py Tue Aug 22 07:55:10 2006 -0700
@@ -23,26 +23,49 @@
# the changeset summary, so you can be sure you are sending the right
# changes.
#
-# It is best to run this script with the "-n" (test only) flag before
-# firing it up "for real", in which case it will use your pager to
-# display each of the messages that it would send.
+# To enable this extension:
#
-# The "-m" (mbox) option will create an mbox file instead of sending
-# the messages directly. This can be reviewed e.g. with "mutt -R -f mbox",
-# and finally sent with "formail -s sendmail -bm -t < mbox".
+# [extensions]
+# hgext.patchbomb =
#
# To configure other defaults, add a section like this to your hgrc
# file:
#
-# [email]
-# from = My Name <my@email>
-# to = recipient1, recipient2, ...
-# cc = cc1, cc2, ...
-# bcc = bcc1, bcc2, ...
+# [email]
+# from = My Name <my@email>
+# to = recipient1, recipient2, ...
+# cc = cc1, cc2, ...
+# bcc = bcc1, bcc2, ...
+#
+# Then you can use the "hg email" command to mail a series of changesets
+# as a patchbomb.
+#
+# To avoid sending patches prematurely, it is a good idea to first run
+# the "email" command with the "-n" option (test only). You will be
+# prompted for an email recipient address, a subject an an introductory
+# message describing the patches of your patchbomb. Then when all is
+# done, your pager will be fired up once for each patchbomb message, so
+# you can verify everything is alright.
+#
+# The "-m" (mbox) option is also very useful. Instead of previewing
+# each patchbomb message in a pager or sending the messages directly,
+# it will create a UNIX mailbox file with the patch emails. This
+# mailbox file can be previewed with any mail user agent which supports
+# UNIX mbox files, i.e. with mutt:
+#
+# % mutt -R -f mbox
+#
+# When you are previewing the patchbomb messages, you can use `formail'
+# (a utility that is commonly installed as part of the procmail package),
+# to send each message out:
+#
+# % formail -s sendmail -bm -t < mbox
+#
+# That should be all. Now your patchbomb is on its way out.
from mercurial.demandload import *
demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils
- mercurial:commands,hg,ui
+ mercurial:commands,hg,mail,ui
os errno popen2 socket sys tempfile time''')
from mercurial.i18n import gettext as _
from mercurial.node import *
@@ -241,7 +264,7 @@
ui.write('\n')
if not opts['test'] and not opts['mbox']:
- mail = ui.sendmail()
+ mailer = mail.connect(ui)
parent = None
# Calculate UTC offset
@@ -290,7 +313,7 @@
ui.status('Sending ', m['Subject'], ' ...\n')
# Exim does not remove the Bcc field
del m['Bcc']
- mail.sendmail(sender, to + bcc + cc, m.as_string(0))
+ mailer.sendmail(sender, to + bcc + cc, m.as_string(0))
cmdtable = {
'email':
--- a/mercurial/archival.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/archival.py Tue Aug 22 07:55:10 2006 -0700
@@ -163,12 +163,12 @@
change = repo.changelog.read(node)
mn = change[0]
archiver = archivers[kind](dest, prefix, mtime or change[2][0])
- mf = repo.manifest.read(mn).items()
- mff = repo.manifest.readflags(mn)
- mf.sort()
+ m = repo.manifest.read(mn)
+ items = m.items()
+ items.sort()
write('.hg_archival.txt', 0644,
'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node)))
- for filename, filenode in mf:
- write(filename, mff[filename] and 0755 or 0644,
+ for filename, filenode in items:
+ write(filename, m.execf(filename) and 0755 or 0644,
repo.file(filename).read(filenode))
archiver.done()
--- a/mercurial/bdiff.c Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/bdiff.c Tue Aug 22 07:55:10 2006 -0700
@@ -1,7 +1,7 @@
/*
bdiff.c - efficient binary diff extension for Mercurial
- Copyright 2005 Matt Mackall <mpm@selenic.com>
+ Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
This software may be used and distributed according to the terms of
the GNU General Public License, incorporated herein by reference.
--- a/mercurial/changelog.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/changelog.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
# changelog.py - changelog class for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/cmdutil.py Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,145 @@
+# cmdutil.py - help for command processing in mercurial
+#
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from demandload import demandload
+from node import *
+from i18n import gettext as _
+demandload(globals(), 'mdiff util')
+demandload(globals(), 'os sys')
+
+def make_filename(repo, pat, node,
+ total=None, seqno=None, revwidth=None, pathname=None):
+ node_expander = {
+ 'H': lambda: hex(node),
+ 'R': lambda: str(repo.changelog.rev(node)),
+ 'h': lambda: short(node),
+ }
+ expander = {
+ '%': lambda: '%',
+ 'b': lambda: os.path.basename(repo.root),
+ }
+
+ try:
+ if node:
+ expander.update(node_expander)
+ if node and revwidth is not None:
+ expander['r'] = (lambda:
+ str(repo.changelog.rev(node)).zfill(revwidth))
+ if total is not None:
+ expander['N'] = lambda: str(total)
+ if seqno is not None:
+ expander['n'] = lambda: str(seqno)
+ if total is not None and seqno is not None:
+ expander['n'] = lambda:str(seqno).zfill(len(str(total)))
+ if pathname is not None:
+ expander['s'] = lambda: os.path.basename(pathname)
+ expander['d'] = lambda: os.path.dirname(pathname) or '.'
+ expander['p'] = lambda: pathname
+
+ newname = []
+ patlen = len(pat)
+ i = 0
+ while i < patlen:
+ c = pat[i]
+ if c == '%':
+ i += 1
+ c = pat[i]
+ c = expander[c]()
+ newname.append(c)
+ i += 1
+ return ''.join(newname)
+ except KeyError, inst:
+ raise util.Abort(_("invalid format spec '%%%s' in output file name"),
+ inst.args[0])
+
+def make_file(repo, pat, node=None,
+ total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
+ if not pat or pat == '-':
+ return 'w' in mode and sys.stdout or sys.stdin
+ if hasattr(pat, 'write') and 'w' in mode:
+ return pat
+ if hasattr(pat, 'read') and 'r' in mode:
+ return pat
+ return open(make_filename(repo, pat, node, total, seqno, revwidth,
+ pathname),
+ mode)
+
+def matchpats(repo, pats=[], opts={}, head=''):
+ cwd = repo.getcwd()
+ if not pats and cwd:
+ opts['include'] = [os.path.join(cwd, i)
+ for i in opts.get('include', [])]
+ opts['exclude'] = [os.path.join(cwd, x)
+ for x in opts.get('exclude', [])]
+ cwd = ''
+ return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
+ opts.get('exclude'), head)
+
+def makewalk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
+ files, matchfn, anypats = matchpats(repo, pats, opts, head)
+ exact = dict(zip(files, files))
+ def walk():
+ for src, fn in repo.walk(node=node, files=files, match=matchfn,
+ badmatch=badmatch):
+ yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
+ return files, matchfn, walk()
+
+def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
+ files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
+ for r in results:
+ yield r
+
+def findrenames(repo, added=None, removed=None, threshold=0.5):
+ if added is None or removed is None:
+ added, removed = repo.status()[1:3]
+ changes = repo.changelog.read(repo.dirstate.parents()[0])
+ mf = repo.manifest.read(changes[0])
+ for a in added:
+ aa = repo.wread(a)
+ bestscore, bestname = None, None
+ for r in removed:
+ rr = repo.file(r).read(mf[r])
+ delta = mdiff.textdiff(aa, rr)
+ if len(delta) < len(aa):
+ myscore = 1.0 - (float(len(delta)) / len(aa))
+ if bestscore is None or myscore > bestscore:
+ bestscore, bestname = myscore, r
+ if bestname and bestscore >= threshold:
+ yield bestname, a, bestscore
+
+def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
+ similarity=None):
+ if dry_run is None:
+ dry_run = opts.get('dry_run')
+ if similarity is None:
+ similarity = float(opts.get('similarity') or 0)
+ add, remove = [], []
+ mapping = {}
+ for src, abs, rel, exact in walk(repo, pats, opts):
+ if src == 'f' and repo.dirstate.state(abs) == '?':
+ add.append(abs)
+ mapping[abs] = rel, exact
+ if repo.ui.verbose or not exact:
+ repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
+ if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
+ remove.append(abs)
+ mapping[abs] = rel, exact
+ if repo.ui.verbose or not exact:
+ repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
+ if not dry_run:
+ repo.add(add, wlock=wlock)
+ repo.remove(remove, wlock=wlock)
+ if similarity > 0:
+ for old, new, score in findrenames(repo, add, remove, similarity):
+ oldrel, oldexact = mapping[old]
+ newrel, newexact = mapping[new]
+ if repo.ui.verbose or not oldexact or not newexact:
+ repo.ui.status(_('recording removal of %s as rename to %s '
+ '(%d%% similar)\n') %
+ (oldrel, newrel, score * 100))
+ if not dry_run:
+ repo.copy(old, new, wlock=wlock)
--- a/mercurial/commands.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/commands.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
# commands.py - command processing for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
@@ -10,10 +10,10 @@
from i18n import gettext as _
demandload(globals(), "os re sys signal shutil imp urllib pdb")
demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
-demandload(globals(), "fnmatch mdiff random signal tempfile time")
+demandload(globals(), "fnmatch difflib patch random signal tempfile time")
demandload(globals(), "traceback errno socket version struct atexit sets bz2")
-demandload(globals(), "archival cStringIO changegroup email.Parser")
-demandload(globals(), "hgweb.server sshserver")
+demandload(globals(), "archival cStringIO changegroup")
+demandload(globals(), "cmdutil hgweb.server sshserver")
class UnknownCommand(Exception):
"""Exception raised if command is not in the command table."""
@@ -21,19 +21,10 @@
"""Exception raised if command shortcut matches more than one command."""
def bail_if_changed(repo):
- modified, added, removed, deleted, unknown = repo.changes()
+ modified, added, removed, deleted = repo.status()[:4]
if modified or added or removed or deleted:
raise util.Abort(_("outstanding uncommitted changes"))
-def filterfiles(filters, files):
- l = [x for x in files if x in filters]
-
- for t in filters:
- if t and t[-1] != "/":
- t += "/"
- l += [x for x in files if x.startswith(t)]
- return l
-
def relpath(repo, args):
cwd = repo.getcwd()
if cwd:
@@ -59,29 +50,6 @@
(logfile, inst.strerror))
return message
-def matchpats(repo, pats=[], opts={}, head=''):
- cwd = repo.getcwd()
- if not pats and cwd:
- opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
- opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
- cwd = ''
- return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
- opts.get('exclude'), head)
-
-def makewalk(repo, pats, opts, node=None, head='', badmatch=None):
- files, matchfn, anypats = matchpats(repo, pats, opts, head)
- exact = dict(zip(files, files))
- def walk():
- for src, fn in repo.walk(node=node, files=files, match=matchfn,
- badmatch=badmatch):
- yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
- return files, matchfn, walk()
-
-def walk(repo, pats, opts, node=None, head='', badmatch=None):
- files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
- for r in results:
- yield r
-
def walkchangerevs(ui, repo, pats, opts):
'''Iterate over files and the revs they changed in.
@@ -124,7 +92,7 @@
windowsize *= 2
- files, matchfn, anypats = matchpats(repo, pats, opts)
+ files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
follow = opts.get('follow') or opts.get('follow_first')
if repo.changelog.count() == 0:
@@ -215,49 +183,59 @@
fncache[rev] = matches
wanted[rev] = 1
- def iterate():
- class followfilter:
- def __init__(self, onlyfirst=False):
- self.startrev = -1
- self.roots = []
- self.onlyfirst = onlyfirst
-
- def match(self, rev):
- def realparents(rev):
- if self.onlyfirst:
- return repo.changelog.parentrevs(rev)[0:1]
- else:
- return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
-
- if self.startrev == -1:
- self.startrev = rev
+ class followfilter:
+ def __init__(self, onlyfirst=False):
+ self.startrev = -1
+ self.roots = []
+ self.onlyfirst = onlyfirst
+
+ def match(self, rev):
+ def realparents(rev):
+ if self.onlyfirst:
+ return repo.changelog.parentrevs(rev)[0:1]
+ else:
+ return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
+
+ if self.startrev == -1:
+ self.startrev = rev
+ return True
+
+ if rev > self.startrev:
+ # forward: all descendants
+ if not self.roots:
+ self.roots.append(self.startrev)
+ for parent in realparents(rev):
+ if parent in self.roots:
+ self.roots.append(rev)
+ return True
+ else:
+ # backwards: all parents
+ if not self.roots:
+ self.roots.extend(realparents(self.startrev))
+ if rev in self.roots:
+ self.roots.remove(rev)
+ self.roots.extend(realparents(rev))
return True
- if rev > self.startrev:
- # forward: all descendants
- if not self.roots:
- self.roots.append(self.startrev)
- for parent in realparents(rev):
- if parent in self.roots:
- self.roots.append(rev)
- return True
- else:
- # backwards: all parents
- if not self.roots:
- self.roots.extend(realparents(self.startrev))
- if rev in self.roots:
- self.roots.remove(rev)
- self.roots.extend(realparents(rev))
- return True
-
- return False
-
+ return False
+
+ # it might be worthwhile to do this in the iterator if the rev range
+ # is descending and the prune args are all within that range
+ for rev in opts.get('prune', ()):
+ rev = repo.changelog.rev(repo.lookup(rev))
+ ff = followfilter()
+ stop = min(revs[0], revs[-1])
+ for x in range(rev, stop-1, -1):
+ if ff.match(x) and wanted.has_key(x):
+ del wanted[x]
+
+ def iterate():
if follow and not files:
ff = followfilter(onlyfirst=opts.get('follow_first'))
def want(rev):
- if rev not in wanted:
- return False
- return ff.match(rev)
+ if ff.match(rev) and rev in wanted:
+ return True
+ return False
else:
def want(rev):
return rev in wanted
@@ -344,63 +322,6 @@
seen[rev] = 1
yield str(rev)
-def make_filename(repo, pat, node,
- total=None, seqno=None, revwidth=None, pathname=None):
- node_expander = {
- 'H': lambda: hex(node),
- 'R': lambda: str(repo.changelog.rev(node)),
- 'h': lambda: short(node),
- }
- expander = {
- '%': lambda: '%',
- 'b': lambda: os.path.basename(repo.root),
- }
-
- try:
- if node:
- expander.update(node_expander)
- if node and revwidth is not None:
- expander['r'] = (lambda:
- str(repo.changelog.rev(node)).zfill(revwidth))
- if total is not None:
- expander['N'] = lambda: str(total)
- if seqno is not None:
- expander['n'] = lambda: str(seqno)
- if total is not None and seqno is not None:
- expander['n'] = lambda:str(seqno).zfill(len(str(total)))
- if pathname is not None:
- expander['s'] = lambda: os.path.basename(pathname)
- expander['d'] = lambda: os.path.dirname(pathname) or '.'
- expander['p'] = lambda: pathname
-
- newname = []
- patlen = len(pat)
- i = 0
- while i < patlen:
- c = pat[i]
- if c == '%':
- i += 1
- c = pat[i]
- c = expander[c]()
- newname.append(c)
- i += 1
- return ''.join(newname)
- except KeyError, inst:
- raise util.Abort(_("invalid format spec '%%%s' in output file name"),
- inst.args[0])
-
-def make_file(repo, pat, node=None,
- total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
- if not pat or pat == '-':
- return 'w' in mode and sys.stdout or sys.stdin
- if hasattr(pat, 'write') and 'w' in mode:
- return pat
- if hasattr(pat, 'read') and 'r' in mode:
- return pat
- return open(make_filename(repo, pat, node, total, seqno, revwidth,
- pathname),
- mode)
-
def write_bundle(cg, filename=None, compress=True):
"""Write a bundle file and return its filename.
@@ -453,74 +374,6 @@
if cleanup is not None:
os.unlink(cleanup)
-def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
- changes=None, text=False, opts={}):
- if not node1:
- node1 = repo.dirstate.parents()[0]
- # reading the data for node1 early allows it to play nicely
- # with repo.changes and the revlog cache.
- change = repo.changelog.read(node1)
- mmap = repo.manifest.read(change[0])
- date1 = util.datestr(change[2])
-
- if not changes:
- changes = repo.changes(node1, node2, files, match=match)
- modified, added, removed, deleted, unknown = changes
- if files:
- modified, added, removed = map(lambda x: filterfiles(files, x),
- (modified, added, removed))
-
- if not modified and not added and not removed:
- return
-
- if node2:
- change = repo.changelog.read(node2)
- mmap2 = repo.manifest.read(change[0])
- _date2 = util.datestr(change[2])
- def date2(f):
- return _date2
- def read(f):
- return repo.file(f).read(mmap2[f])
- else:
- tz = util.makedate()[1]
- _date2 = util.datestr()
- def date2(f):
- try:
- return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
- except OSError, err:
- if err.errno != errno.ENOENT: raise
- return _date2
- def read(f):
- return repo.wread(f)
-
- if ui.quiet:
- r = None
- else:
- hexfunc = ui.verbose and hex or short
- r = [hexfunc(node) for node in [node1, node2] if node]
-
- diffopts = ui.diffopts()
- showfunc = opts.get('show_function') or diffopts['showfunc']
- ignorews = opts.get('ignore_all_space') or diffopts['ignorews']
- ignorewsamount = opts.get('ignore_space_change') or \
- diffopts['ignorewsamount']
- ignoreblanklines = opts.get('ignore_blank_lines') or \
- diffopts['ignoreblanklines']
-
- all = modified + added + removed
- all.sort()
- for f in all:
- to = None
- tn = None
- if f in mmap:
- to = repo.file(f).read(mmap[f])
- if f not in removed:
- tn = read(f)
- fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
- showfunc=showfunc, ignorews=ignorews,
- ignorewsamount=ignorewsamount,
- ignoreblanklines=ignoreblanklines))
-
def trimuser(ui, name, rev, revcache):
"""trim the name of the user who committed a change"""
user = revcache.get(rev)
@@ -550,17 +403,15 @@
changes = log.read(changenode)
date = util.datestr(changes[2])
- parents = [(log.rev(p), self.ui.verbose and hex(p) or short(p))
- for p in log.parents(changenode)
+ hexfunc = self.ui.debugflag and hex or short
+
+ parents = [(log.rev(p), hexfunc(p)) for p in log.parents(changenode)
if self.ui.debugflag or p != nullid]
if (not self.ui.debugflag and len(parents) == 1 and
parents[0][0] == rev-1):
parents = []
- if self.ui.verbose:
- self.ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
- else:
- self.ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
+ self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
for tag in self.repo.nodetags(changenode):
self.ui.status(_("tag: %s\n") % tag)
@@ -577,7 +428,7 @@
self.ui.status(_("date: %s\n") % date)
if self.ui.debugflag:
- files = self.repo.changes(log.parents(changenode)[0], changenode)
+ files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
for key, value in zip([_("files:"), _("files+:"), _("files-:")],
files):
if value:
@@ -633,7 +484,7 @@
ui.write(_("Mercurial Distributed SCM (version %s)\n")
% version.get_version())
ui.status(_(
- "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
+ "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
"This is free software; see the source for copying conditions. "
"There is NO\nwarranty; "
"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
@@ -654,7 +505,7 @@
if with_version:
show_version(ui)
ui.write('\n')
- aliases, i = findcmd(name)
+ aliases, i = findcmd(ui, name)
# synopsis
ui.write("%s\n\n" % i[2])
@@ -787,7 +638,7 @@
"""
names = []
- for src, abs, rel, exact in walk(repo, pats, opts):
+ for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
if exact:
if ui.verbose:
ui.status(_('adding %s\n') % rel)
@@ -801,33 +652,21 @@
def addremove(ui, repo, *pats, **opts):
"""add all new files, delete all missing files (DEPRECATED)
- (DEPRECATED)
Add all new files and remove all missing files from the repository.
New files are ignored if they match any of the patterns in .hgignore. As
with add, these changes take effect at the next commit.
- This command is now deprecated and will be removed in a future
- release. Please use add and remove --after instead.
+ Use the -s option to detect renamed files. With a parameter > 0,
+ this compares every removed file with every added file and records
+ those similar enough as renames. This option takes a percentage
+ between 0 (disabled) and 100 (files must be identical) as its
+ parameter. Detecting renamed files this way can be expensive.
"""
- ui.warn(_('(the addremove command is deprecated; use add and remove '
- '--after instead)\n'))
- return addremove_lock(ui, repo, pats, opts)
-
-def addremove_lock(ui, repo, pats, opts, wlock=None):
- add, remove = [], []
- for src, abs, rel, exact in walk(repo, pats, opts):
- if src == 'f' and repo.dirstate.state(abs) == '?':
- add.append(abs)
- if ui.verbose or not exact:
- ui.status(_('adding %s\n') % ((pats and rel) or abs))
- if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
- remove.append(abs)
- if ui.verbose or not exact:
- ui.status(_('removing %s\n') % ((pats and rel) or abs))
- if not opts.get('dry_run'):
- repo.add(add, wlock=wlock)
- repo.remove(remove, wlock=wlock)
+ sim = float(opts.get('similarity') or 0)
+ if sim < 0 or sim > 100:
+ raise util.Abort(_('similarity must be between 0 and 100'))
+ return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
def annotate(ui, repo, *pats, **opts):
"""show changeset information per file line
@@ -870,7 +709,8 @@
ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
- for src, abs, rel, exact in walk(repo, pats, opts, node=ctx.node()):
+ for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
+ node=ctx.node()):
fctx = ctx.filectx(abs)
if not opts['text'] and util.binary(fctx.data()):
ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
@@ -922,10 +762,10 @@
raise util.Abort(_('uncommitted merge - please provide a '
'specific revision'))
- dest = make_filename(repo, dest, node)
+ dest = cmdutil.make_filename(repo, dest, node)
if os.path.realpath(dest) == repo.root:
raise util.Abort(_('repository root cannot be destination'))
- dummy, matchfn, dummy = matchpats(repo, [], opts)
+ dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
kind = opts.get('type') or 'files'
prefix = opts['prefix']
if dest == '-':
@@ -933,7 +773,7 @@
raise util.Abort(_('cannot archive plain files to stdout'))
dest = sys.stdout
if not prefix: prefix = os.path.basename(repo.root) + '-%h'
- prefix = make_filename(repo, prefix, node)
+ prefix = cmdutil.make_filename(repo, prefix, node)
archival.archive(repo, dest, node, kind, not opts['no_decode'],
matchfn, prefix)
@@ -978,6 +818,7 @@
parent = p1
hg.clean(repo, node, show_stats=False)
revert_opts = opts.copy()
+ revert_opts['all'] = True
revert_opts['rev'] = hex(parent)
revert(ui, repo, **revert_opts)
commit_opts = opts.copy()
@@ -1037,8 +878,9 @@
%p root-relative path name of file being printed
"""
ctx = repo.changectx(opts['rev'] or "-1")
- for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, ctx.node()):
- fp = make_file(repo, opts['output'], ctx.node(), pathname=abs)
+ for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
+ ctx.node()):
+ fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
fp.write(ctx.filectx(abs).data())
def clone(ui, source, dest=None, **opts):
@@ -1100,11 +942,10 @@
message = logmessage(opts)
if opts['addremove']:
- addremove_lock(ui, repo, pats, opts)
- fns, match, anypats = matchpats(repo, pats, opts)
+ cmdutil.addremove(repo, pats, opts)
+ fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
if pats:
- modified, added, removed, deleted, unknown = (
- repo.changes(files=fns, match=match))
+ modified, added, removed = repo.status(files=fns, match=match)[:3]
files = modified + added + removed
else:
files = []
@@ -1259,7 +1100,7 @@
copylist = []
for pat in pats:
srcs = []
- for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
+ for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
origsrc = okaytocopy(abssrc, relsrc, exact)
if origsrc:
srcs.append((origsrc, abssrc, relsrc, exact))
@@ -1311,7 +1152,7 @@
options = []
otables = [globalopts]
if cmd:
- aliases, entry = findcmd(cmd)
+ aliases, entry = findcmd(ui, cmd)
otables.append(entry[1])
for t in otables:
for o in t:
@@ -1321,7 +1162,7 @@
ui.write("%s\n" % "\n".join(options))
return
- clist = findpossible(cmd).keys()
+ clist = findpossible(ui, cmd).keys()
clist.sort()
ui.write("%s\n" % "\n".join(clist))
@@ -1333,9 +1174,9 @@
rev = repo.lookup(rev)
change = repo.changelog.read(rev)
n = change[0]
- files = repo.manifest.readflags(n)
+ files = repo.manifest.read(n)
wlock = repo.wlock()
- repo.dirstate.rebuild(rev, files.iteritems())
+ repo.dirstate.rebuild(rev, files)
def debugcheckstate(ui, repo):
"""validate the correctness of the current dirstate"""
@@ -1476,7 +1317,7 @@
def debugwalk(ui, repo, *pats, **opts):
"""show how files match on given patterns"""
- items = list(walk(repo, pats, opts))
+ items = list(cmdutil.walk(repo, pats, opts))
if not items:
return
fmt = '%%s %%-%ds %%-%ds %%s' % (
@@ -1505,37 +1346,10 @@
"""
node1, node2 = revpair(ui, repo, opts['rev'])
- fns, matchfn, anypats = matchpats(repo, pats, opts)
-
- dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
- text=opts['text'], opts=opts)
-
-def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
- node = repo.lookup(changeset)
- parents = [p for p in repo.changelog.parents(node) if p != nullid]
- if opts['switch_parent']:
- parents.reverse()
- prev = (parents and parents[0]) or nullid
- change = repo.changelog.read(node)
-
- fp = make_file(repo, opts['output'], node, total=total, seqno=seqno,
- revwidth=revwidth)
- if fp != sys.stdout:
- ui.note("%s\n" % fp.name)
-
- fp.write("# HG changeset patch\n")
- fp.write("# User %s\n" % change[1])
- fp.write("# Date %d %d\n" % change[2])
- fp.write("# Node ID %s\n" % hex(node))
- fp.write("# Parent %s\n" % hex(prev))
- if len(parents) > 1:
- fp.write("# Parent %s\n" % hex(parents[1]))
- fp.write(change[4].rstrip())
- fp.write("\n\n")
-
- dodiff(fp, ui, repo, prev, node, text=opts['text'])
- if fp != sys.stdout:
- fp.close()
+ fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
+
+ patch.diff(repo, node1, node2, fns, match=matchfn,
+ opts=patch.diffopts(ui, opts))
def export(ui, repo, *changesets, **opts):
"""dump the header and diffs for one or more changesets
@@ -1566,15 +1380,14 @@
"""
if not changesets:
raise util.Abort(_("export requires at least one changeset"))
- seqno = 0
revs = list(revrange(ui, repo, changesets))
- total = len(revs)
- revwidth = max(map(len, revs))
- msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
- ui.note(msg)
- for cset in revs:
- seqno += 1
- doexport(ui, repo, cset, seqno, total, revwidth, opts)
+ if len(revs) > 1:
+ ui.note(_('exporting patches:\n'))
+ else:
+ ui.note(_('exporting patch:\n'))
+ patch.export(repo, map(repo.lookup, revs), template=opts['output'],
+ switch_parent=opts['switch_parent'],
+ opts=patch.diffopts(ui, opts))
def forget(ui, repo, *pats, **opts):
"""don't add the specified files on the next commit (DEPRECATED)
@@ -1587,7 +1400,7 @@
"""
ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
forget = []
- for src, abs, rel, exact in walk(repo, pats, opts):
+ for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
if repo.dirstate.state(abs) == 'a':
forget.append(abs)
if ui.verbose or not exact:
@@ -1644,42 +1457,56 @@
self.linenum = linenum
self.colstart = colstart
self.colend = colend
+
def __eq__(self, other):
return self.line == other.line
- def __hash__(self):
- return hash(self.line)
matches = {}
+ copies = {}
def grepbody(fn, rev, body):
- matches[rev].setdefault(fn, {})
+ matches[rev].setdefault(fn, [])
m = matches[rev][fn]
for lnum, cstart, cend, line in matchlines(body):
s = linestate(line, lnum, cstart, cend)
- m[s] = s
-
- # FIXME: prev isn't used, why ?
+ m.append(s)
+
+ def difflinestates(a, b):
+ sm = difflib.SequenceMatcher(None, a, b)
+ for tag, alo, ahi, blo, bhi in sm.get_opcodes():
+ if tag == 'insert':
+ for i in range(blo, bhi):
+ yield ('+', b[i])
+ elif tag == 'delete':
+ for i in range(alo, ahi):
+ yield ('-', a[i])
+ elif tag == 'replace':
+ for i in range(alo, ahi):
+ yield ('-', a[i])
+ for i in range(blo, bhi):
+ yield ('+', b[i])
+
prev = {}
ucache = {}
def display(fn, rev, states, prevstates):
- diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
- diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
counts = {'-': 0, '+': 0}
filerevmatches = {}
- for l in diff:
+ if incrementing or not opts['all']:
+ a, b = prevstates, states
+ else:
+ a, b = states, prevstates
+ for change, l in difflinestates(a, b):
if incrementing or not opts['all']:
- change = ((l in prevstates) and '-') or '+'
r = rev
else:
- change = ((l in states) and '-') or '+'
r = prev[fn]
- cols = [fn, str(rev)]
+ cols = [fn, str(r)]
if opts['line_number']:
cols.append(str(l.linenum))
if opts['all']:
cols.append(change)
if opts['user']:
- cols.append(trimuser(ui, getchange(rev)[1], rev,
- ucache))
+ cols.append(trimuser(ui, getchange(r)[1], rev,
+ ucache))
if opts['files_with_matches']:
c = (fn, rev)
if c in filerevmatches:
@@ -1696,6 +1523,7 @@
changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
count = 0
incrementing = False
+ follow = opts.get('follow')
for st, rev, fns in changeiter:
if st == 'window':
incrementing = rev
@@ -1710,20 +1538,31 @@
fstate.setdefault(fn, {})
try:
grepbody(fn, rev, getfile(fn).read(mf[fn]))
+ if follow:
+ copied = getfile(fn).renamed(mf[fn])
+ if copied:
+ copies.setdefault(rev, {})[fn] = copied[0]
except KeyError:
pass
elif st == 'iter':
states = matches[rev].items()
states.sort()
for fn, m in states:
+ copy = copies.get(rev, {}).get(fn)
if fn in skip:
+ if copy:
+ skip[copy] = True
continue
if incrementing or not opts['all'] or fstate[fn]:
pos, neg = display(fn, rev, m, fstate[fn])
count += pos + neg
if pos and not opts['all']:
skip[fn] = True
+ if copy:
+ skip[copy] = True
fstate[fn] = m
+ if copy:
+ fstate[copy] = m
prev[fn] = rev
if not incrementing:
@@ -1732,7 +1571,8 @@
for fn, state in fstate:
if fn in skip:
continue
- display(fn, rev, {}, state)
+ if fn not in copies.get(prev[fn], {}):
+ display(fn, rev, {}, state)
return (count == 0 and 1) or 0
def heads(ui, repo, **opts):
@@ -1769,8 +1609,8 @@
ui.write(_("unknown\n"))
return
- hexfunc = ui.verbose and hex or short
- modified, added, removed, deleted, unknown = repo.changes()
+ hexfunc = ui.debugflag and hex or short
+ modified, added, removed, deleted = repo.status()[:4]
output = ["%s%s" %
('+'.join([hexfunc(parent) for parent in parents]),
(modified or added or removed or deleted) and "+" or "")]
@@ -1814,81 +1654,23 @@
d = opts["base"]
strip = opts["strip"]
- mailre = re.compile(r'(?:From |[\w-]+:)')
-
- # attempt to detect the start of a patch
- # (this heuristic is borrowed from quilt)
- diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
- 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
- '(---|\*\*\*)[ \t])', re.MULTILINE)
-
- for patch in patches:
- pf = os.path.join(d, patch)
-
- message = None
- user = None
- date = None
- hgpatch = False
-
- p = email.Parser.Parser()
+ wlock = repo.wlock()
+ lock = repo.lock()
+
+ for p in patches:
+ pf = os.path.join(d, p)
+
if pf == '-':
- msg = p.parse(sys.stdin)
ui.status(_("applying patch from stdin\n"))
+ tmpname, message, user, date = patch.extract(ui, sys.stdin)
else:
- msg = p.parse(file(pf))
- ui.status(_("applying %s\n") % patch)
-
- fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
- tmpfp = os.fdopen(fd, 'w')
+ ui.status(_("applying %s\n") % p)
+ tmpname, message, user, date = patch.extract(ui, file(pf))
+
+ if tmpname is None:
+ raise util.Abort(_('no diffs found'))
+
try:
- message = msg['Subject']
- if message:
- message = message.replace('\n\t', ' ')
- ui.debug('Subject: %s\n' % message)
- user = msg['From']
- if user:
- ui.debug('From: %s\n' % user)
- diffs_seen = 0
- ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
- for part in msg.walk():
- content_type = part.get_content_type()
- ui.debug('Content-Type: %s\n' % content_type)
- if content_type not in ok_types:
- continue
- payload = part.get_payload(decode=True)
- m = diffre.search(payload)
- if m:
- ui.debug(_('found patch at byte %d\n') % m.start(0))
- diffs_seen += 1
- hgpatch = False
- fp = cStringIO.StringIO()
- if message:
- fp.write(message)
- fp.write('\n')
- for line in payload[:m.start(0)].splitlines():
- if line.startswith('# HG changeset patch'):
- ui.debug(_('patch generated by hg export\n'))
- hgpatch = True
- # drop earlier commit message content
- fp.seek(0)
- fp.truncate()
- elif hgpatch:
- if line.startswith('# User '):
- user = line[7:]
- ui.debug('From: %s\n' % user)
- elif line.startswith("# Date "):
- date = line[7:]
- if not line.startswith('# '):
- fp.write(line)
- fp.write('\n')
- message = fp.getvalue()
- if tmpfp:
- tmpfp.write(payload)
- if not payload.endswith('\n'):
- tmpfp.write('\n')
- elif not diffs_seen and message and content_type == 'text/plain':
- message += '\n' + payload
-
if opts['message']:
# pickup the cmdline msg
message = opts['message']
@@ -1900,18 +1682,9 @@
message = None
ui.debug(_('message:\n%s\n') % message)
- tmpfp.close()
- if not diffs_seen:
- raise util.Abort(_('no diffs found'))
-
- files = util.patch(strip, tmpname, ui, cwd=repo.root)
- if len(files) > 0:
- cfiles = files
- cwd = repo.getcwd()
- if cwd:
- cfiles = [util.pathto(cwd, f) for f in files]
- addremove_lock(ui, repo, cfiles, {})
- repo.commit(files, message, user, date)
+ files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root)
+ files = patch.updatedir(ui, repo, files, wlock=wlock)
+ repo.commit(files, message, user, date, wlock=wlock, lock=lock)
finally:
os.unlink(tmpname)
@@ -1964,7 +1737,7 @@
displayer.show(changenode=n)
if opts['patch']:
prev = (parents and parents[0]) or nullid
- dodiff(ui, ui, other, prev, n)
+ patch.diff(other, prev, n, fp=repo.ui)
ui.write("\n")
finally:
if hasattr(other, 'close'):
@@ -2012,8 +1785,8 @@
else:
node = None
- for src, abs, rel, exact in walk(repo, pats, opts, node=node,
- head='(?:.*/|)'):
+ for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
+ head='(?:.*/|)'):
if not node and repo.dirstate.state(abs) == '?':
continue
if opts['fullpath']:
@@ -2115,7 +1888,7 @@
displayer.show(rev, brinfo=br)
if opts['patch']:
prev = (parents and parents[0]) or nullid
- dodiff(du, du, repo, prev, changenode, match=matchfn)
+ patch.diff(repo, prev, changenode, match=matchfn, fp=du)
du.write("\n\n")
elif st == 'iter':
if count == limit: break
@@ -2146,12 +1919,12 @@
else:
n = repo.manifest.tip()
m = repo.manifest.read(n)
- mf = repo.manifest.readflags(n)
files = m.keys()
files.sort()
for f in files:
- ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
+ ui.write("%40s %3s %s\n" % (hex(m[f]),
+ m.execf(f) and "755" or "644", f))
def merge(ui, repo, node=None, force=None, branch=None):
"""Merge working directory with another revision
@@ -2160,9 +1933,29 @@
requested revision. Files that changed between either parent are
marked as changed for the next commit and a commit must be
performed before any further updates are allowed.
+
+ If no revision is specified, the working directory's parent is a
+ head revision, and the repository contains exactly one other head,
+ the other head is merged with by default. Otherwise, an explicit
+ revision to merge with must be provided.
"""
- node = _lookup(repo, node, branch)
+ if node:
+ node = _lookup(repo, node, branch)
+ else:
+ heads = repo.heads()
+ if len(heads) > 2:
+ raise util.Abort(_('repo has %d heads - '
+ 'please merge with an explicit rev') %
+ len(heads))
+ if len(heads) == 1:
+ raise util.Abort(_('there is nothing to merge - '
+ 'use "hg update" instead'))
+ parent = repo.dirstate.parents()[0]
+ if parent not in heads:
+ raise util.Abort(_('working dir not at a head rev - '
+ 'use "hg update" or merge with an explicit rev'))
+ node = parent == heads[0] and heads[-1] or heads[0]
return hg.merge(repo, node, force=force)
def outgoing(ui, repo, dest=None, **opts):
@@ -2196,7 +1989,7 @@
displayer.show(changenode=n)
if opts['patch']:
prev = (parents and parents[0]) or nullid
- dodiff(ui, ui, repo, prev, n)
+ patch.diff(repo, prev, n)
ui.write("\n")
def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
@@ -2409,12 +2202,12 @@
names = []
if not opts['after'] and not pats:
raise util.Abort(_('no files specified'))
- files, matchfn, anypats = matchpats(repo, pats, opts)
+ files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
exact = dict.fromkeys(files)
- mardu = map(dict.fromkeys, repo.changes(files=files, match=matchfn))
+ mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
modified, added, removed, deleted, unknown = mardu
remove, forget = [], []
- for src, abs, rel, exact in walk(repo, pats, opts):
+ for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
reason = None
if abs not in deleted and opts['after']:
reason = _('is still present')
@@ -2494,8 +2287,12 @@
If names are given, all files matching the names are reverted.
- If no arguments are given, all files in the repository are reverted.
+ If no arguments are given, no files are reverted.
"""
+
+ if not pats and not opts['all']:
+ raise util.Abort(_('no files or directories specified'))
+
parent, p2 = repo.dirstate.parents()
if opts['rev']:
node = repo.lookup(opts['rev'])
@@ -2521,20 +2318,21 @@
# walk dirstate.
- for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key):
+ for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
+ badmatch=mf.has_key):
names[abs] = (rel, exact)
if src == 'b':
target_only[abs] = True
# walk target manifest.
- for src, abs, rel, exact in walk(repo, pats, opts, node=node,
- badmatch=names.has_key):
+ for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
+ badmatch=names.has_key):
if abs in names: continue
names[abs] = (rel, exact)
target_only[abs] = True
- changes = repo.changes(match=names.has_key, wlock=wlock)
+ changes = repo.status(match=names.has_key, wlock=wlock)[:5]
modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
revert = ([], _('reverting %s\n'))
@@ -2741,7 +2539,7 @@
all = opts['all']
- files, matchfn, anypats = matchpats(repo, pats, opts)
+ files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
cwd = (pats and repo.getcwd()) or ''
modified, added, removed, deleted, unknown, ignored, clean = [
[util.pathto(cwd, x) for x in n]
@@ -2801,17 +2599,20 @@
if opts['rev']:
rev_ = opts['rev']
if rev_:
- r = hex(repo.lookup(rev_))
+ r = repo.lookup(rev_)
else:
p1, p2 = repo.dirstate.parents()
if p1 == nullid:
raise util.Abort(_('no revision to tag'))
if p2 != nullid:
raise util.Abort(_('outstanding uncommitted merges'))
- r = hex(p1)
-
- repo.tag(name, r, opts['local'], opts['message'], opts['user'],
- opts['date'])
+ r = p1
+
+ message = opts['message']
+ if not message:
+ message = _('Added tag %s for changeset %s') % (name, short(r))
+
+ repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
def tags(ui, repo):
"""list repository tags
@@ -2823,9 +2624,10 @@
l = repo.tagslist()
l.reverse()
+ hexfunc = ui.debugflag and hex or short
for t, n in l:
try:
- r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
+ r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
except KeyError:
r = " ?:?"
if ui.quiet:
@@ -2844,7 +2646,7 @@
br = repo.branchlookup([n])
show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
if opts['patch']:
- dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
+ patch.diff(repo, repo.changelog.parents(n)[0], n)
def unbundle(ui, repo, fname, **opts):
"""apply a changegroup file
@@ -2957,11 +2759,14 @@
('X', 'exclude', [], _('exclude names matching the given patterns')),
('n', 'dry-run', None, _('do not perform actions, just print output'))],
_('hg add [OPTION]... [FILE]...')),
- "debugaddremove|addremove":
+ "addremove":
(addremove,
[('I', 'include', [], _('include names matching the given patterns')),
('X', 'exclude', [], _('exclude names matching the given patterns')),
- ('n', 'dry-run', None, _('do not perform actions, just print output'))],
+ ('n', 'dry-run', None,
+ _('do not perform actions, just print output')),
+ ('s', 'similarity', '',
+ _('guess renamed files by similarity (0<=s<=1)'))],
_('hg addremove [OPTION]... [FILE]...')),
"^annotate":
(annotate,
@@ -3067,6 +2872,7 @@
('a', 'text', None, _('treat all files as text')),
('p', 'show-function', None,
_('show which function each change is in')),
+ ('g', 'git', None, _('use git extended diff format')),
('w', 'ignore-all-space', None,
_('ignore white space when comparing lines')),
('b', 'ignore-space-change', None,
@@ -3091,6 +2897,8 @@
(grep,
[('0', 'print0', None, _('end fields with NUL')),
('', 'all', None, _('print all revisions that match')),
+ ('f', 'follow', None,
+ _('follow changeset history, or file history across copies and renames')),
('i', 'ignore-case', None, _('ignore case when matching')),
('l', 'files-with-matches', None,
_('print only filenames and revs that match')),
@@ -3127,7 +2935,7 @@
('n', 'newest-first', None, _('show newest record first')),
('', 'bundle', '', _('file to store the bundles into')),
('p', 'patch', None, _('show patch')),
- ('r', 'rev', [], _('a specific revision you would like to pull')),
+ ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
('', 'template', '', _('display with template')),
('e', 'ssh', '', _('specify ssh command to use')),
('', 'remotecmd', '',
@@ -3164,6 +2972,7 @@
('', 'style', '', _('display using template map file')),
('m', 'only-merges', None, _('show only merges')),
('p', 'patch', None, _('show patch')),
+ ('P', 'prune', [], _('do not display revision or any of its ancestors')),
('', 'template', '', _('display with template')),
('I', 'include', [], _('include names matching the given patterns')),
('X', 'exclude', [], _('exclude names matching the given patterns'))],
@@ -3202,7 +3011,7 @@
('e', 'ssh', '', _('specify ssh command to use')),
('f', 'force', None,
_('run even when remote repository is unrelated')),
- ('r', 'rev', [], _('a specific revision you would like to pull')),
+ ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
('', 'remotecmd', '',
_('specify hg command to run on the remote side'))],
_('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
@@ -3242,7 +3051,8 @@
_('hg rename [OPTION]... SOURCE... DEST')),
"^revert":
(revert,
- [('r', 'rev', '', _('revision to revert to')),
+ [('a', 'all', None, _('revert all changes when no arguments given')),
+ ('r', 'rev', '', _('revision to revert to')),
('', 'no-backup', None, _('do not save backup copies of files')),
('I', 'include', [], _('include names matching given patterns')),
('X', 'exclude', [], _('exclude names matching given patterns')),
@@ -3341,7 +3151,7 @@
" debugindex debugindexdot")
optionalrepo = ("paths serve debugconfig")
-def findpossible(cmd):
+def findpossible(ui, cmd):
"""
Return cmd -> (aliases, command table entry)
for each matching command.
@@ -3354,7 +3164,7 @@
found = None
if cmd in aliases:
found = cmd
- else:
+ elif not ui.config("ui", "strict"):
for a in aliases:
if a.startswith(cmd):
found = a
@@ -3370,9 +3180,9 @@
return choice
-def findcmd(cmd):
+def findcmd(ui, cmd):
"""Return (aliases, command table entry) for command string."""
- choice = findpossible(cmd)
+ choice = findpossible(ui, cmd)
if choice.has_key(cmd):
return choice[cmd]
@@ -3407,7 +3217,7 @@
if args:
cmd, args = args[0], args[1:]
- aliases, i = findcmd(cmd)
+ aliases, i = findcmd(ui, cmd)
cmd = aliases[0]
defaults = ui.config("defaults", cmd)
if defaults:
@@ -3446,18 +3256,11 @@
return sys.modules[v]
raise KeyError(name)
-def dispatch(args):
- for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
- num = getattr(signal, name, None)
- if num: signal.signal(num, catchterm)
-
- try:
- u = ui.ui(traceback='--traceback' in sys.argv[1:])
- except util.Abort, inst:
- sys.stderr.write(_("abort: %s\n") % inst)
- return -1
-
- for ext_name, load_from_name in u.extensions():
+def load_extensions(ui):
+ added = []
+ for ext_name, load_from_name in ui.extensions():
+ if ext_name in external:
+ continue
try:
if load_from_name:
# the module will be loaded in sys.modules
@@ -3477,23 +3280,36 @@
except ImportError:
mod = importh(ext_name)
external[ext_name] = mod.__name__
+ added.append((mod, ext_name))
except (util.SignalInterrupt, KeyboardInterrupt):
raise
except Exception, inst:
- u.warn(_("*** failed to import extension %s: %s\n") % (ext_name, inst))
- if u.print_exc():
+ ui.warn(_("*** failed to import extension %s: %s\n") %
+ (ext_name, inst))
+ if ui.print_exc():
return 1
- for name in external.itervalues():
- mod = sys.modules[name]
+ for mod, name in added:
uisetup = getattr(mod, 'uisetup', None)
if uisetup:
- uisetup(u)
+ uisetup(ui)
cmdtable = getattr(mod, 'cmdtable', {})
for t in cmdtable:
if t in table:
- u.warn(_("module %s overrides %s\n") % (name, t))
+ ui.warn(_("module %s overrides %s\n") % (name, t))
table.update(cmdtable)
+
+def dispatch(args):
+ for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
+ num = getattr(signal, name, None)
+ if num: signal.signal(num, catchterm)
+
+ try:
+ u = ui.ui(traceback='--traceback' in sys.argv[1:],
+ readhooks=[load_extensions])
+ except util.Abort, inst:
+ sys.stderr.write(_("abort: %s\n") % inst)
+ return -1
try:
cmd, func, args, options, cmdoptions = parse(u, args)
@@ -3545,6 +3361,7 @@
mod = sys.modules[name]
if hasattr(mod, 'reposetup'):
mod.reposetup(u, repo)
+ hg.repo_setup_hooks.append(mod.reposetup)
except hg.RepoError:
if cmd not in optionalrepo.split():
raise
--- a/mercurial/context.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/context.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
# context.py - changeset and file context objects for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/demandload.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/demandload.py Tue Aug 22 07:55:10 2006 -0700
@@ -109,9 +109,9 @@
mod = mod[:col]
else:
fromlist = []
- as = None
+ as_ = None
if '@' in mod:
- mod, as = mod.split("@")
+ mod, as_ = mod.split("@")
importer = _importer(scope, mod, fromlist)
if fromlist:
for name in fromlist:
@@ -130,6 +130,6 @@
continue
else:
basemod = mod
- if not as:
- as = basemod
- scope[as] = _replacer(importer, as)
+ if not as_:
+ as_ = basemod
+ scope[as_] = _replacer(importer, as_)
--- a/mercurial/dirstate.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/dirstate.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,7 +1,7 @@
"""
dirstate.py - working directory tracking for mercurial
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
@@ -10,7 +10,7 @@
from node import *
from i18n import gettext as _
from demandload import *
-demandload(globals(), "struct os time bisect stat util re errno")
+demandload(globals(), "struct os time bisect stat strutil util re errno")
class dirstate(object):
format = ">cllll"
@@ -22,6 +22,7 @@
self.ui = ui
self.map = None
self.pl = None
+ self.dirs = None
self.copies = {}
self.ignorefunc = None
self.blockignore = False
@@ -197,6 +198,38 @@
def copied(self, file):
return self.copies.get(file, None)
+ def initdirs(self):
+ if self.dirs is None:
+ self.dirs = {}
+ for f in self.map:
+ self.updatedirs(f, 1)
+
+ def updatedirs(self, path, delta):
+ if self.dirs is not None:
+ for c in strutil.findall(path, '/'):
+ pc = path[:c]
+ self.dirs.setdefault(pc, 0)
+ self.dirs[pc] += delta
+
+ def checkshadows(self, files):
+ def prefixes(f):
+ for c in strutil.rfindall(f, '/'):
+ yield f[:c]
+ self.lazyread()
+ self.initdirs()
+ seendirs = {}
+ for f in files:
+ if self.dirs.get(f):
+ raise util.Abort(_('directory named %r already in dirstate') %
+ f)
+ for d in prefixes(f):
+ if d in seendirs:
+ break
+ if d in self.map:
+ raise util.Abort(_('file named %r already in dirstate') %
+ d)
+ seendirs[d] = True
+
def update(self, files, state, **kw):
''' current states:
n normal
@@ -207,10 +240,16 @@
if not files: return
self.lazyread()
self.markdirty()
+ if state == "a":
+ self.initdirs()
+ self.checkshadows(files)
for f in files:
if state == "r":
self.map[f] = ('r', 0, 0, 0)
+ self.updatedirs(f, -1)
else:
+ if state == "a":
+ self.updatedirs(f, 1)
s = os.lstat(self.wjoin(f))
st_size = kw.get('st_size', s.st_size)
st_mtime = kw.get('st_mtime', s.st_mtime)
@@ -222,9 +261,11 @@
if not files: return
self.lazyread()
self.markdirty()
+ self.initdirs()
for f in files:
try:
del self.map[f]
+ self.updatedirs(f, -1)
except KeyError:
self.ui.warn(_("not in dirstate: %s!\n") % f)
pass
@@ -232,14 +273,15 @@
def clear(self):
self.map = {}
self.copies = {}
+ self.dirs = None
self.markdirty()
def rebuild(self, parent, files):
self.clear()
umask = os.umask(0)
os.umask(umask)
- for f, mode in files:
- if mode:
+ for f in files:
+ if files.execf(f):
self.map[f] = ('n', ~umask, -1, 0)
else:
self.map[f] = ('n', ~umask & 0666, -1, 0)
@@ -476,7 +518,7 @@
if size >= 0 and (size != st.st_size
or (mode ^ st.st_mode) & 0100):
modified.append(fn)
- elif time != st.st_mtime:
+ elif time != int(st.st_mtime):
lookup.append(fn)
elif list_clean:
clean.append(fn)
--- a/mercurial/filelog.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/filelog.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
# filelog.py - file history class for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
@@ -65,6 +65,26 @@
return (m["copy"], bin(m["copyrev"]))
return False
+ def size(self, rev):
+ """return the size of a given revision"""
+
+ # for revisions with renames, we have to go the slow way
+ node = self.node(rev)
+ if self.renamed(node):
+ return len(self.read(node))
+
+ return revlog.size(self, rev)
+
+ def cmp(self, node, text):
+ """compare text with a given file revision"""
+
+ # for renames, we have to go the slow way
+ if self.renamed(node):
+ t2 = self.read(node)
+ return t2 != text
+
+ return revlog.cmp(self, node, text)
+
def annotate(self, node):
def decorate(text, rev):
@@ -76,31 +96,59 @@
return child
# find all ancestors
- needed = {node:1}
- visit = [node]
+ needed = {(self, node):1}
+ files = [self]
+ visit = [(self, node)]
while visit:
- n = visit.pop(0)
- for p in self.parents(n):
- if p not in needed:
- needed[p] = 1
- visit.append(p)
+ f, n = visit.pop(0)
+ rn = f.renamed(n)
+ if rn:
+ f, n = rn
+ f = filelog(self.opener, f, self.defversion)
+ files.insert(0, f)
+ if (f, n) not in needed:
+ needed[(f, n)] = 1
+ else:
+ needed[(f, n)] += 1
+ for p in f.parents(n):
+ if p == nullid:
+ continue
+ if (f, p) not in needed:
+ needed[(f, p)] = 1
+ visit.append((f, p))
else:
# count how many times we'll use this
- needed[p] += 1
+ needed[(f, p)] += 1
- # sort by revision which is a topological order
- visit = [ (self.rev(n), n) for n in needed.keys() ]
- visit.sort()
+ # sort by revision (per file) which is a topological order
+ visit = []
+ for f in files:
+ fn = [(f.rev(n[1]), f, n[1]) for n in needed.keys() if n[0] == f]
+ fn.sort()
+ visit.extend(fn)
hist = {}
- for r,n in visit:
- curr = decorate(self.read(n), self.linkrev(n))
- for p in self.parents(n):
+ for i in range(len(visit)):
+ r, f, n = visit[i]
+ curr = decorate(f.read(n), f.linkrev(n))
+ if r == -1:
+ continue
+ parents = f.parents(n)
+ # follow parents across renames
+ if r < 1 and i > 0:
+ j = i
+ while j > 0 and visit[j][1] == f:
+ j -= 1
+ parents = (visit[j][2],)
+ f = visit[j][1]
+ else:
+ parents = f.parents(n)
+ for p in parents:
if p != nullid:
curr = pair(hist[p], curr)
# trim the history of unneeded revs
- needed[p] -= 1
- if not needed[p]:
+ needed[(f, p)] -= 1
+ if not needed[(f, p)]:
del hist[p]
hist[n] = curr
--- a/mercurial/hg.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/hg.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,7 @@
# hg.py - repository classes for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
@@ -48,9 +49,14 @@
return False
return repo.local()
+repo_setup_hooks = []
+
def repository(ui, path=None, create=False):
"""return a repository object for the specified path"""
- return _lookup(path).instance(ui, path, create)
+ repo = _lookup(path).instance(ui, path, create)
+ for hook in repo_setup_hooks:
+ hook(ui, repo)
+ return repo
def defaultdest(source):
'''return default destination of clone if none is given'''
--- a/mercurial/hgweb/common.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/hgweb/common.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,7 +1,7 @@
# hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hgweb/hgweb_mod.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/hgweb/hgweb_mod.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,7 +1,7 @@
# hgweb/hgweb_mod.py - Web interface for a repository.
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
@@ -11,7 +11,7 @@
import mimetypes
from mercurial.demandload import demandload
demandload(globals(), "re zlib ConfigParser mimetools cStringIO sys tempfile")
-demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone")
+demandload(globals(), "mercurial:mdiff,ui,hg,util,archival,streamclone,patch")
demandload(globals(), "mercurial:templater")
demandload(globals(), "mercurial.hgweb.common:get_mtime,staticfile")
from mercurial.node import *
@@ -129,37 +129,27 @@
date1 = util.datestr(change1[2])
date2 = util.datestr(change2[2])
- modified, added, removed, deleted, unknown = r.changes(node1, node2)
+ modified, added, removed, deleted, unknown = r.status(node1, node2)[:5]
if files:
modified, added, removed = map(lambda x: filterfiles(files, x),
(modified, added, removed))
- diffopts = self.repo.ui.diffopts()
- showfunc = diffopts['showfunc']
- ignorews = diffopts['ignorews']
- ignorewsamount = diffopts['ignorewsamount']
- ignoreblanklines = diffopts['ignoreblanklines']
+ diffopts = patch.diffopts(self.repo.ui)
for f in modified:
to = r.file(f).read(mmap1[f])
tn = r.file(f).read(mmap2[f])
yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
- showfunc=showfunc, ignorews=ignorews,
- ignorewsamount=ignorewsamount,
- ignoreblanklines=ignoreblanklines), f, tn)
+ opts=diffopts), f, tn)
for f in added:
to = None
tn = r.file(f).read(mmap2[f])
yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
- showfunc=showfunc, ignorews=ignorews,
- ignorewsamount=ignorewsamount,
- ignoreblanklines=ignoreblanklines), f, tn)
+ opts=diffopts), f, tn)
for f in removed:
to = r.file(f).read(mmap1[f])
tn = None
yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
- showfunc=showfunc, ignorews=ignorews,
- ignorewsamount=ignorewsamount,
- ignoreblanklines=ignoreblanklines), f, tn)
+ opts=diffopts), f, tn)
def changelog(self, pos, shortlog=False):
def changenav(**map):
@@ -398,7 +388,7 @@
parent=self.siblings(fl.parents(n), fl.rev, file=f),
child=self.siblings(fl.children(n), fl.rev, file=f),
rename=self.renamelink(fl, n),
- permissions=self.repo.manifest.readflags(mfn)[f])
+ permissions=self.repo.manifest.read(mfn).execf(f))
def fileannotate(self, f, node):
bcache = {}
@@ -452,7 +442,7 @@
rename=self.renamelink(fl, n),
parent=self.siblings(fl.parents(n), fl.rev, file=f),
child=self.siblings(fl.children(n), fl.rev, file=f),
- permissions=self.repo.manifest.readflags(mfn)[f])
+ permissions=self.repo.manifest.read(mfn).execf(f))
def manifest(self, mnode, path):
man = self.repo.manifest
@@ -462,7 +452,6 @@
rev = man.rev(mn)
changerev = man.linkrev(mn)
node = self.repo.changelog.node(changerev)
- mff = man.readflags(mn)
files = {}
@@ -496,7 +485,7 @@
"filenode": hex(fnode),
"parity": self.stripes(parity),
"basename": f,
- "permissions": mff[full]}
+ "permissions": mf.execf(full)}
parity += 1
def dirlist(**map):
--- a/mercurial/hgweb/hgwebdir_mod.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/hgweb/hgwebdir_mod.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,7 +1,7 @@
# hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hgweb/request.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/hgweb/request.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,7 +1,7 @@
# hgweb/request.py - An http request from either CGI or the standalone server.
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/hgweb/server.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/hgweb/server.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,7 +1,7 @@
# hgweb/server.py - The standalone hg web server.
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/httprangereader.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/httprangereader.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
# httprangereader.py - just what it says
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/httprepo.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/httprepo.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,7 @@
# httprepo.py - HTTP repository proxy classes for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/i18n.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/i18n.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,7 +1,7 @@
"""
i18n.py - internationalization support for mercurial
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/localrepo.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/localrepo.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
# localrepo.py - read/write repository class for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
@@ -169,7 +169,7 @@
tag_disallowed = ':\r\n'
- def tag(self, name, node, local=False, message=None, user=None, date=None):
+ def tag(self, name, node, message, local, user, date):
'''tag a revision with a symbolic name.
if local is True, the tag is stored in a per-repository file.
@@ -191,27 +191,24 @@
if c in name:
raise util.Abort(_('%r cannot be used in a tag name') % c)
- self.hook('pretag', throw=True, node=node, tag=name, local=local)
+ self.hook('pretag', throw=True, node=hex(node), tag=name, local=local)
if local:
- self.opener('localtags', 'a').write('%s %s\n' % (node, name))
- self.hook('tag', node=node, tag=name, local=local)
+ self.opener('localtags', 'a').write('%s %s\n' % (hex(node), name))
+ self.hook('tag', node=hex(node), tag=name, local=local)
return
- for x in self.changes():
+ for x in self.status()[:5]:
if '.hgtags' in x:
raise util.Abort(_('working copy of .hgtags is changed '
'(please commit .hgtags manually)'))
- self.wfile('.hgtags', 'ab').write('%s %s\n' % (node, name))
+ self.wfile('.hgtags', 'ab').write('%s %s\n' % (hex(node), name))
if self.dirstate.state('.hgtags') == '?':
self.add(['.hgtags'])
- if not message:
- message = _('Added tag %s for changeset %s') % (name, node)
-
self.commit(['.hgtags'], message, user, date)
- self.hook('tag', node=node, tag=name, local=local)
+ self.hook('tag', node=hex(node), tag=name, local=local)
def tags(self):
'''return a mapping of tag to node'''
@@ -470,8 +467,7 @@
p2 = p2 or self.dirstate.parents()[1] or nullid
c1 = self.changelog.read(p1)
c2 = self.changelog.read(p2)
- m1 = self.manifest.read(c1[0])
- mf1 = self.manifest.readflags(c1[0])
+ m1 = self.manifest.read(c1[0]).copy()
m2 = self.manifest.read(c2[0])
changed = []
@@ -484,36 +480,32 @@
wlock = self.wlock()
l = self.lock()
tr = self.transaction()
- mm = m1.copy()
- mfm = mf1.copy()
linkrev = self.changelog.count()
for f in files:
try:
t = self.wread(f)
- tm = util.is_exec(self.wjoin(f), mfm.get(f, False))
+ m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
r = self.file(f)
- mfm[f] = tm
(entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2)
if entry:
- mm[f] = entry
+ m1[f] = entry
continue
- mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
+ m1[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
changed.append(f)
if update_dirstate:
self.dirstate.update([f], "n")
except IOError:
try:
- del mm[f]
- del mfm[f]
+ del m1[f]
if update_dirstate:
self.dirstate.forget([f])
except:
# deleted from p2?
pass
- mnode = self.manifest.add(mm, mfm, tr, linkrev, c1[0], c2[0])
+ mnode = self.manifest.add(m1, tr, linkrev, c1[0], c2[0])
user = user or self.ui.username()
n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
tr.close()
@@ -537,15 +529,14 @@
else:
self.ui.warn(_("%s not tracked!\n") % f)
else:
- modified, added, removed, deleted, unknown = self.changes(match=match)
+ modified, added, removed, deleted, unknown = self.status(match=match)[:5]
commit = modified + added
remove = removed
p1, p2 = self.dirstate.parents()
c1 = self.changelog.read(p1)
c2 = self.changelog.read(p2)
- m1 = self.manifest.read(c1[0])
- mf1 = self.manifest.readflags(c1[0])
+ m1 = self.manifest.read(c1[0]).copy()
m2 = self.manifest.read(c2[0])
if not commit and not remove and not force and p2 == nullid:
@@ -571,7 +562,7 @@
for f in commit:
self.ui.note(f + "\n")
try:
- mf1[f] = util.is_exec(self.wjoin(f), mf1.get(f, False))
+ m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
t = self.wread(f)
except IOError:
self.ui.warn(_("trouble committing %s!\n") % f)
@@ -598,12 +589,11 @@
changed.append(f)
# update manifest
- m1 = m1.copy()
m1.update(new)
for f in remove:
if f in m1:
del m1[f]
- mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0],
+ mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0],
(new, remove))
# add changeset
@@ -675,8 +665,7 @@
def fcmp(fn, mf):
t1 = self.wread(fn)
- t2 = self.file(fn).read(mf.get(fn, nullid))
- return cmp(t1, t2)
+ return self.file(fn).cmp(mf.get(fn, nullid), t1)
def mfmatches(node):
change = self.changelog.read(node)
@@ -718,8 +707,10 @@
for f in lookup:
if fcmp(f, mf2):
modified.append(f)
- elif wlock is not None:
- self.dirstate.update([f], "n")
+ else:
+ clean.append(f)
+ if wlock is not None:
+ self.dirstate.update([f], "n")
else:
# we are comparing working dir against non-parent
# generate a pseudo-manifest for the working dir
@@ -758,16 +749,6 @@
l.sort()
return (modified, added, removed, deleted, unknown, ignored, clean)
- def changes(self, node1=None, node2=None, files=[], match=util.always,
- wlock=None, list_ignored=False, list_clean=False):
- '''DEPRECATED - use status instead'''
- marduit = self.status(node1, node2, files, match, wlock,
- list_ignored, list_clean)
- if list_ignored:
- return marduit[:-1]
- else:
- return marduit[:-2]
-
def add(self, list, wlock=None):
if not wlock:
wlock = self.wlock()
@@ -816,7 +797,6 @@
def undelete(self, list, wlock=None):
p = self.dirstate.parents()[0]
mn = self.changelog.read(p)[0]
- mf = self.manifest.readflags(mn)
m = self.manifest.read(mn)
if not wlock:
wlock = self.wlock()
@@ -826,7 +806,7 @@
else:
t = self.file(f).read(m[f])
self.wwrite(f, t)
- util.set_exec(self.wjoin(f), mf[f])
+ util.set_exec(self.wjoin(f), m.execf(f))
self.dirstate.update([f], "n")
def copy(self, source, dest, wlock=None):
@@ -1122,7 +1102,7 @@
else:
raise util.Abort(_("repository is unrelated"))
- self.ui.note(_("found new changesets starting at ") +
+ self.ui.debug(_("found new changesets starting at ") +
" ".join([short(f) for f in fetch]) + "\n")
self.ui.debug(_("%d total queries\n") % reqcnt)
--- a/mercurial/lock.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/lock.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
# lock.py - simple locking scheme for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/mail.py Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,68 @@
+# mail.py - mail sending bits for mercurial
+#
+# Copyright 2006 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from i18n import gettext as _
+from demandload import *
+demandload(globals(), "os re smtplib templater util")
+
+def _smtp(ui):
+ '''send mail using smtp.'''
+
+ local_hostname = ui.config('smtp', 'local_hostname')
+ s = smtplib.SMTP(local_hostname=local_hostname)
+ mailhost = ui.config('smtp', 'host')
+ if not mailhost:
+ raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
+ mailport = int(ui.config('smtp', 'port', 25))
+ ui.note(_('sending mail: smtp host %s, port %s\n') %
+ (mailhost, mailport))
+ s.connect(host=mailhost, port=mailport)
+ if ui.configbool('smtp', 'tls'):
+ ui.note(_('(using tls)\n'))
+ s.ehlo()
+ s.starttls()
+ s.ehlo()
+ username = ui.config('smtp', 'username')
+ password = ui.config('smtp', 'password')
+ if username and password:
+ ui.note(_('(authenticating to mail server as %s)\n') %
+ (username))
+ s.login(username, password)
+ return s
+
+class _sendmail(object):
+ '''send mail using sendmail.'''
+
+ def __init__(self, ui, program):
+ self.ui = ui
+ self.program = program
+
+ def sendmail(self, sender, recipients, msg):
+ cmdline = '%s -f %s %s' % (
+ self.program, templater.email(sender),
+ ' '.join(map(templater.email, recipients)))
+ self.ui.note(_('sending mail: %s\n') % cmdline)
+ fp = os.popen(cmdline, 'w')
+ fp.write(msg)
+ ret = fp.close()
+ if ret:
+ raise util.Abort('%s %s' % (
+ os.path.basename(self.program.split(None, 1)[0]),
+ util.explain_exit(ret)[0]))
+
+def connect(ui):
+ '''make a mail connection. object returned has one method, sendmail.
+ call as sendmail(sender, list-of-recipients, msg).'''
+
+ method = ui.config('email', 'method', 'smtp')
+ if method == 'smtp':
+ return _smtp(ui)
+
+ return _sendmail(ui, method)
+
+def sendmail(ui, sender, recipients, msg):
+ return connect(ui).sendmail(sender, recipients, msg)
--- a/mercurial/manifest.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/manifest.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
# manifest.py - manifest revision class for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
@@ -10,6 +10,31 @@
from demandload import *
demandload(globals(), "array bisect struct")
+class manifestdict(dict):
+ def __init__(self, mapping=None, flags=None):
+ if mapping is None: mapping = {}
+ if flags is None: flags = {}
+ dict.__init__(self, mapping)
+ self._flags = flags
+ def flags(self, f):
+ return self._flags.get(f, "")
+ def execf(self, f):
+ "test for executable in manifest flags"
+ return "x" in self.flags(f)
+ def linkf(self, f):
+ "test for symlink in manifest flags"
+ return "l" in self.flags(f)
+ def rawset(self, f, entry):
+ self[f] = bin(entry[:40])
+ fl = entry[40:-1]
+ if fl: self._flags[f] = fl
+ def set(self, f, execf=False, linkf=False):
+ if linkf: self._flags[f] = "l"
+ elif execf: self._flags[f] = "x"
+ else: self._flags[f] = ""
+ def copy(self):
+ return manifestdict(dict.copy(self), dict.copy(self._flags))
+
class manifest(revlog):
def __init__(self, opener, defversion=REVLOGV0):
self.mapcache = None
@@ -18,26 +43,18 @@
defversion)
def read(self, node):
- if node == nullid: return {} # don't upset local cache
+ if node == nullid: return manifestdict() # don't upset local cache
if self.mapcache and self.mapcache[0] == node:
return self.mapcache[1]
text = self.revision(node)
- map = {}
- flag = {}
self.listcache = array.array('c', text)
lines = text.splitlines(1)
+ mapping = manifestdict()
for l in lines:
(f, n) = l.split('\0')
- map[f] = bin(n[:40])
- flag[f] = (n[40:-1] == "x")
- self.mapcache = (node, map, flag)
- return map
-
- def readflags(self, node):
- if node == nullid: return {} # don't upset local cache
- if not self.mapcache or self.mapcache[0] != node:
- self.read(node)
- return self.mapcache[2]
+ mapping.rawset(f, n)
+ self.mapcache = (node, mapping)
+ return mapping
def diff(self, a, b):
return mdiff.textdiff(str(a), str(b))
@@ -86,7 +103,7 @@
'''look up entry for a single file efficiently.
return (node, flag) pair if found, (None, None) if not.'''
if self.mapcache and node == self.mapcache[0]:
- return self.mapcache[1].get(f), self.mapcache[2].get(f)
+ return self.mapcache[1].get(f), self.mapcache[1].flags(f)
text = self.revision(node)
start, end = self._search(text, f)
if start == end:
@@ -95,7 +112,7 @@
f, n = l.split('\0')
return bin(n[:40]), n[40:-1] == 'x'
- def add(self, map, flags, transaction, link, p1=None, p2=None,
+ def add(self, map, transaction, link, p1=None, p2=None,
changed=None):
# apply the changes collected during the bisect loop to our addlist
# return a delta suitable for addrevision
@@ -123,9 +140,7 @@
# if this is changed to support newlines in filenames,
# be sure to check the templates/ dir again (especially *-raw.tmpl)
- text = ["%s\000%s%s\n" %
- (f, hex(map[f]), flags[f] and "x" or '')
- for f in files]
+ text = ["%s\000%s%s\n" % (f, hex(map[f]), map.flags(f)) for f in files]
self.listcache = array.array('c', "".join(text))
cachedelta = None
else:
@@ -151,8 +166,7 @@
# bs will either be the index of the item or the insert point
start, end = self._search(addbuf, f, start)
if w[1] == 0:
- l = "%s\000%s%s\n" % (f, hex(map[f]),
- flags[f] and "x" or '')
+ l = "%s\000%s%s\n" % (f, hex(map[f]), map.flags(f))
else:
l = ""
if start == end and w[1] == 1:
@@ -183,6 +197,6 @@
n = self.addrevision(buffer(self.listcache), transaction, link, p1, \
p2, cachedelta)
- self.mapcache = (n, map, flags)
+ self.mapcache = (n, map)
return n
--- a/mercurial/mdiff.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/mdiff.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
# mdiff.py - diff and patch routines for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
@@ -19,14 +19,41 @@
lines[-1] = lines[-1][:-1]
return lines
-def unidiff(a, ad, b, bd, fn, r=None, text=False,
- showfunc=False, ignorews=False, ignorewsamount=False,
- ignoreblanklines=False):
+class diffopts(object):
+ '''context is the number of context lines
+ text treats all files as text
+ showfunc enables diff -p output
+ git enables the git extended patch format
+ ignorews ignores all whitespace changes in the diff
+ ignorewsamount ignores changes in the amount of whitespace
+ ignoreblanklines ignores changes whose lines are all blank'''
+ defaults = {
+ 'context': 3,
+ 'text': False,
+ 'showfunc': True,
+ 'git': False,
+ 'ignorews': False,
+ 'ignorewsamount': False,
+ 'ignoreblanklines': False,
+ }
+
+ __slots__ = defaults.keys()
+
+ def __init__(self, **opts):
+ for k in self.__slots__:
+ v = opts.get(k)
+ if v is None:
+ v = self.defaults[k]
+ setattr(self, k, v)
+
+defaultopts = diffopts()
+
+def unidiff(a, ad, b, bd, fn, r=None, opts=defaultopts):
if not a and not b: return ""
epoch = util.datestr((0, 0))
- if not text and (util.binary(a) or util.binary(b)):
+ if not opts.text and (util.binary(a) or util.binary(b)):
l = ['Binary file %s has changed\n' % fn]
elif not a:
b = splitnewlines(b)
@@ -49,10 +76,7 @@
else:
al = splitnewlines(a)
bl = splitnewlines(b)
- l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn,
- showfunc=showfunc, ignorews=ignorews,
- ignorewsamount=ignorewsamount,
- ignoreblanklines=ignoreblanklines))
+ l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn, opts=opts))
if not l: return ""
# difflib uses a space, rather than a tab
l[0] = "%s\t%s\n" % (l[0][:-2], ad)
@@ -72,21 +96,15 @@
# t1 and t2 are the text to be diffed
# l1 and l2 are the text broken up into lines
# header1 and header2 are the filenames for the diff output
-# context is the number of context lines
-# showfunc enables diff -p output
-# ignorews ignores all whitespace changes in the diff
-# ignorewsamount ignores changes in the amount of whitespace
-# ignoreblanklines ignores changes whose lines are all blank
-def bunidiff(t1, t2, l1, l2, header1, header2, context=3, showfunc=False,
- ignorews=False, ignorewsamount=False, ignoreblanklines=False):
+def bunidiff(t1, t2, l1, l2, header1, header2, opts=defaultopts):
def contextend(l, len):
- ret = l + context
+ ret = l + opts.context
if ret > len:
ret = len
return ret
def contextstart(l):
- ret = l - context
+ ret = l - opts.context
if ret < 0:
return 0
return ret
@@ -101,7 +119,7 @@
blen = b2 - bstart + aend - a2
func = ""
- if showfunc:
+ if opts.showfunc:
# walk backwards from the start of the context
# to find a line starting with an alphanumeric char.
for x in xrange(astart, -1, -1):
@@ -119,14 +137,14 @@
header = [ "--- %s\t\n" % header1, "+++ %s\t\n" % header2 ]
- if showfunc:
+ if opts.showfunc:
funcre = re.compile('\w')
- if ignorewsamount:
+ if opts.ignorewsamount:
wsamountre = re.compile('[ \t]+')
wsappendedre = re.compile(' \n')
- if ignoreblanklines:
+ if opts.ignoreblanklines:
wsblanklinesre = re.compile('\n')
- if ignorews:
+ if opts.ignorews:
wsre = re.compile('[ \t]')
# bdiff.blocks gives us the matching sequences in the files. The loop
@@ -159,13 +177,13 @@
if not old and not new:
continue
- if ignoreblanklines:
+ if opts.ignoreblanklines:
wsold = wsblanklinesre.sub('', "".join(old))
wsnew = wsblanklinesre.sub('', "".join(new))
if wsold == wsnew:
continue
- if ignorewsamount:
+ if opts.ignorewsamount:
wsold = wsamountre.sub(' ', "".join(old))
wsold = wsappendedre.sub('\n', wsold)
wsnew = wsamountre.sub(' ', "".join(new))
@@ -173,7 +191,7 @@
if wsold == wsnew:
continue
- if ignorews:
+ if opts.ignorews:
wsold = wsre.sub('', "".join(old))
wsnew = wsre.sub('', "".join(new))
if wsold == wsnew:
@@ -184,7 +202,7 @@
prev = None
if hunk:
# join with the previous hunk if it falls inside the context
- if astart < hunk[1] + context + 1:
+ if astart < hunk[1] + opts.context + 1:
prev = hunk
astart = hunk[1]
bstart = hunk[3]
--- a/mercurial/merge.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/merge.py Tue Aug 22 07:55:10 2006 -0700
@@ -10,6 +10,11 @@
from demandload import *
demandload(globals(), "util os tempfile")
+def fmerge(f, local, other, ancestor):
+ """merge executable flags"""
+ a, b, c = ancestor.execf(f), local.execf(f), other.execf(f)
+ return ((a^b) | (a^c)) ^ a
+
def merge3(repo, fn, my, other, p1, p2):
"""perform a 3-way merge in the working directory"""
@@ -75,7 +80,7 @@
raise util.Abort(_("update spans branches, use 'hg merge' "
"or 'hg update -C' to lose changes"))
- modified, added, removed, deleted, unknown = repo.changes()
+ modified, added, removed, deleted, unknown = repo.status()[:5]
if branchmerge and not forcemerge:
if modified or added or removed:
raise util.Abort(_("outstanding uncommitted changes"))
@@ -84,18 +89,13 @@
m2n = repo.changelog.read(p2)[0]
man = repo.manifest.ancestor(m1n, m2n)
m1 = repo.manifest.read(m1n)
- mf1 = repo.manifest.readflags(m1n)
m2 = repo.manifest.read(m2n).copy()
- mf2 = repo.manifest.readflags(m2n)
ma = repo.manifest.read(man)
- mfa = repo.manifest.readflags(man)
- if not forcemerge and not overwrite:
+ if not force:
for f in unknown:
if f in m2:
- t1 = repo.wread(f)
- t2 = repo.file(f).read(m2[f])
- if cmp(t1, t2) != 0:
+ if repo.file(f).cmp(m2[f], repo.wread(f)):
raise util.Abort(_("'%s' already exists in the working"
" dir and differs from remote") % f)
@@ -103,22 +103,27 @@
# we care about merging
repo.ui.note(_("resolving manifests\n"))
repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") %
- (overwrite, branchmerge, partial and True or False, linear_path))
+ (overwrite, branchmerge, bool(partial), linear_path))
repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
(short(man), short(m1n), short(m2n)))
merge = {}
get = {}
remove = []
+ forget = []
# construct a working dir manifest
mw = m1.copy()
- mfw = mf1.copy()
umap = dict.fromkeys(unknown)
for f in added + modified + unknown:
mw[f] = ""
- mfw[f] = util.is_exec(repo.wjoin(f), mfw.get(f, False))
+ # is the wfile new and matches m2?
+ if (f not in m1 and f in m2 and
+ not repo.file(f).cmp(m2[f], repo.wread(f))):
+ mw[f] = m2[f]
+
+ mw.set(f, util.is_exec(repo.wjoin(f), mw.execf(f)))
for f in deleted + removed:
if f in mw:
@@ -129,8 +134,8 @@
# the file, then we need to remove it from the dirstate, to
# prevent the dirstate from listing the file when it is no
# longer in the manifest.
- if not partial and linear_path and f not in m2:
- repo.dirstate.forget((f,))
+ if linear_path and f not in m2:
+ forget.append(f)
# Compare manifests
for f, n in mw.iteritems():
@@ -139,46 +144,32 @@
if f in m2:
s = 0
- # is the wfile new since m1, and match m2?
- if f not in m1:
- t1 = repo.wread(f)
- t2 = repo.file(f).read(m2[f])
- if cmp(t1, t2) == 0:
- n = m2[f]
- del t1, t2
-
# are files different?
if n != m2[f]:
a = ma.get(f, nullid)
# are both different from the ancestor?
if n != a and m2[f] != a:
repo.ui.debug(_(" %s versions differ, resolve\n") % f)
- # merge executable bits
- # "if we changed or they changed, change in merge"
- a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
- mode = ((a^b) | (a^c)) ^ a
- merge[f] = (m1.get(f, nullid), m2[f], mode)
+ merge[f] = (fmerge(f, mw, m2, ma), m1.get(f, nullid), m2[f])
s = 1
# are we clobbering?
# is remote's version newer?
# or are we going back in time?
elif overwrite or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
repo.ui.debug(_(" remote %s is newer, get\n") % f)
- get[f] = m2[f]
+ get[f] = (m2.execf(f), m2[f])
s = 1
elif f in umap or f in added:
# this unknown file is the same as the checkout
# we need to reset the dirstate if the file was added
- get[f] = m2[f]
+ get[f] = (m2.execf(f), m2[f])
- if not s and mfw[f] != mf2[f]:
+ if not s and mw.execf(f) != m2.execf(f):
if overwrite:
repo.ui.debug(_(" updating permissions for %s\n") % f)
- util.set_exec(repo.wjoin(f), mf2[f])
+ util.set_exec(repo.wjoin(f), m2.execf(f))
else:
- a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
- mode = ((a^b) | (a^c)) ^ a
- if mode != b:
+ if fmerge(f, mw, m2, ma) != mw.execf(f):
repo.ui.debug(_(" updating permissions for %s\n")
% f)
util.set_exec(repo.wjoin(f), mode)
@@ -221,22 +212,24 @@
(_("remote changed %s which local deleted\n") % f) +
_("(k)eep or (d)elete?"), _("[kd]"), _("k"))
if r == _("k"):
- get[f] = n
+ get[f] = (m2.execf(f), n)
elif f not in ma:
repo.ui.debug(_("remote created %s\n") % f)
- get[f] = n
+ get[f] = (m2.execf(f), n)
else:
if overwrite or p2 == pa: # going backwards?
repo.ui.debug(_("local deleted %s, recreating\n") % f)
- get[f] = n
+ get[f] = (m2.execf(f), n)
else:
repo.ui.debug(_("local deleted %s\n") % f)
del mw, m1, m2, ma
+ ### apply phase
+
if overwrite:
for f in merge:
- get[f] = merge[f][1]
+ get[f] = merge[f][:2]
merge = {}
if linear_path or overwrite:
@@ -254,17 +247,13 @@
files = get.keys()
files.sort()
for f in files:
+ flag, node = get[f]
if f[0] == "/":
continue
repo.ui.note(_("getting %s\n") % f)
- t = repo.file(f).read(get[f])
+ t = repo.file(f).read(node)
repo.wwrite(f, t)
- util.set_exec(repo.wjoin(f), mf2[f])
- if not partial:
- if branchmerge:
- repo.dirstate.update([f], 'n', st_mtime=-1)
- else:
- repo.dirstate.update([f], 'n')
+ util.set_exec(repo.wjoin(f), flag)
# merge the tricky bits
unresolved = []
@@ -272,24 +261,11 @@
files.sort()
for f in files:
repo.ui.status(_("merging %s\n") % f)
- my, other, flag = merge[f]
+ flag, my, other = merge[f]
ret = merge3(repo, f, my, other, xp1, xp2)
if ret:
unresolved.append(f)
util.set_exec(repo.wjoin(f), flag)
- if not partial:
- if branchmerge:
- # We've done a branch merge, mark this file as merged
- # so that we properly record the merger later
- repo.dirstate.update([f], 'm')
- else:
- # We've update-merged a locally modified file, so
- # we set the dirstate to emulate a normal checkout
- # of that file some time in the past. Thus our
- # merge will appear as a normal local file
- # modification.
- f_len = len(repo.file(f).read(other))
- repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
remove.sort()
for f in remove:
@@ -301,14 +277,40 @@
if inst.errno != errno.ENOENT:
repo.ui.warn(_("update failed to remove %s: %s!\n") %
(f, inst.strerror))
+
+ # update dirstate
if not partial:
+ repo.dirstate.setparents(p1, p2)
+ repo.dirstate.forget(forget)
if branchmerge:
repo.dirstate.update(remove, 'r')
else:
repo.dirstate.forget(remove)
- if not partial:
- repo.dirstate.setparents(p1, p2)
+ files = get.keys()
+ files.sort()
+ for f in files:
+ if branchmerge:
+ repo.dirstate.update([f], 'n', st_mtime=-1)
+ else:
+ repo.dirstate.update([f], 'n')
+
+ files = merge.keys()
+ files.sort()
+ for f in files:
+ if branchmerge:
+ # We've done a branch merge, mark this file as merged
+ # so that we properly record the merger later
+ repo.dirstate.update([f], 'm')
+ else:
+ # We've update-merged a locally modified file, so
+ # we set the dirstate to emulate a normal checkout
+ # of that file some time in the past. Thus our
+ # merge will appear as a normal local file
+ # modification.
+ fl = repo.file(f)
+ f_len = fl.size(fl.rev(other))
+ repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
if show_stats:
stats = ((len(get), _("updated")),
--- a/mercurial/mpatch.c Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/mpatch.c Tue Aug 22 07:55:10 2006 -0700
@@ -14,7 +14,7 @@
allocation of intermediate Python objects. Working memory is about 2x
the total number of hunks.
- Copyright 2005 Matt Mackall <mpm@selenic.com>
+ Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/node.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/node.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,7 +1,7 @@
"""
node.py - basic nodeid manipulation for mercurial
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/packagescan.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/packagescan.py Tue Aug 22 07:55:10 2006 -0700
@@ -2,7 +2,7 @@
# Used for the py2exe distutil.
# This module must be the first mercurial module imported in setup.py
#
-# Copyright 2005 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
+# Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
@@ -39,9 +39,9 @@
except:
module = m
fromlist = []
- as = None
+ as_ = None
if '@' in module:
- module, as = module.split("@")
+ module, as_ = module.split('@')
mod = __import__(module, scope, scope, fromlist)
if fromlist == []:
# mod is only the top package, but we need all packages
@@ -50,9 +50,9 @@
mn = comp[0]
while True:
# mn and mod.__name__ might not be the same
- if not as:
- as = mn
- scope[as] = mod
+ if not as_:
+ as_ = mn
+ scope[as_] = mod
requiredmodules[mod.__name__] = 1
if len(comp) == i: break
mod = getattr(mod,comp[i])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/patch.py Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,539 @@
+# patch.py - patch file parsing routines
+#
+# Copyright 2006 Brendan Cully <brendan@kublai.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+from demandload import demandload
+from i18n import gettext as _
+from node import *
+demandload(globals(), "cmdutil mdiff util")
+demandload(globals(), "cStringIO email.Parser errno os re shutil sys tempfile")
+
+# helper functions
+
+def copyfile(src, dst, basedir=None):
+ if not basedir:
+ basedir = os.getcwd()
+
+ abssrc, absdst = [os.path.join(basedir, n) for n in (src, dst)]
+ if os.path.exists(absdst):
+ raise util.Abort(_("cannot create %s: destination already exists") %
+ dst)
+
+ targetdir = os.path.dirname(absdst)
+ if not os.path.isdir(targetdir):
+ os.makedirs(targetdir)
+ try:
+ shutil.copyfile(abssrc, absdst)
+ shutil.copymode(abssrc, absdst)
+ except shutil.Error, inst:
+ raise util.Abort(str(inst))
+
+# public functions
+
+def extract(ui, fileobj):
+ '''extract patch from data read from fileobj.
+
+ patch can be normal patch or contained in email message.
+
+ return tuple (filename, message, user, date). any item in returned
+ tuple can be None. if filename is None, fileobj did not contain
+ patch. caller must unlink filename when done.'''
+
+ # attempt to detect the start of a patch
+ # (this heuristic is borrowed from quilt)
+ diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
+ 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
+ '(---|\*\*\*)[ \t])', re.MULTILINE)
+
+ fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
+ tmpfp = os.fdopen(fd, 'w')
+ try:
+ hgpatch = False
+
+ msg = email.Parser.Parser().parse(fileobj)
+
+ message = msg['Subject']
+ user = msg['From']
+ # should try to parse msg['Date']
+ date = None
+
+ if message:
+ message = message.replace('\n\t', ' ')
+ ui.debug('Subject: %s\n' % message)
+ if user:
+ ui.debug('From: %s\n' % user)
+ diffs_seen = 0
+ ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
+
+ for part in msg.walk():
+ content_type = part.get_content_type()
+ ui.debug('Content-Type: %s\n' % content_type)
+ if content_type not in ok_types:
+ continue
+ payload = part.get_payload(decode=True)
+ m = diffre.search(payload)
+ if m:
+ ui.debug(_('found patch at byte %d\n') % m.start(0))
+ diffs_seen += 1
+ cfp = cStringIO.StringIO()
+ if message:
+ cfp.write(message)
+ cfp.write('\n')
+ for line in payload[:m.start(0)].splitlines():
+ if line.startswith('# HG changeset patch'):
+ ui.debug(_('patch generated by hg export\n'))
+ hgpatch = True
+ # drop earlier commit message content
+ cfp.seek(0)
+ cfp.truncate()
+ elif hgpatch:
+ if line.startswith('# User '):
+ user = line[7:]
+ ui.debug('From: %s\n' % user)
+ elif line.startswith("# Date "):
+ date = line[7:]
+ if not line.startswith('# '):
+ cfp.write(line)
+ cfp.write('\n')
+ message = cfp.getvalue()
+ if tmpfp:
+ tmpfp.write(payload)
+ if not payload.endswith('\n'):
+ tmpfp.write('\n')
+ elif not diffs_seen and message and content_type == 'text/plain':
+ message += '\n' + payload
+ except:
+ tmpfp.close()
+ os.unlink(tmpname)
+ raise
+
+ tmpfp.close()
+ if not diffs_seen:
+ os.unlink(tmpname)
+ return None, message, user, date
+ return tmpname, message, user, date
+
+def readgitpatch(patchname):
+ """extract git-style metadata about patches from <patchname>"""
+ class gitpatch:
+ "op is one of ADD, DELETE, RENAME, MODIFY or COPY"
+ def __init__(self, path):
+ self.path = path
+ self.oldpath = None
+ self.mode = None
+ self.op = 'MODIFY'
+ self.copymod = False
+ self.lineno = 0
+
+ # Filter patch for git information
+ gitre = re.compile('diff --git a/(.*) b/(.*)')
+ pf = file(patchname)
+ gp = None
+ gitpatches = []
+ # Can have a git patch with only metadata, causing patch to complain
+ dopatch = False
+
+ lineno = 0
+ for line in pf:
+ lineno += 1
+ if line.startswith('diff --git'):
+ m = gitre.match(line)
+ if m:
+ if gp:
+ gitpatches.append(gp)
+ src, dst = m.group(1,2)
+ gp = gitpatch(dst)
+ gp.lineno = lineno
+ elif gp:
+ if line.startswith('--- '):
+ if gp.op in ('COPY', 'RENAME'):
+ gp.copymod = True
+ dopatch = 'filter'
+ gitpatches.append(gp)
+ gp = None
+ if not dopatch:
+ dopatch = True
+ continue
+ if line.startswith('rename from '):
+ gp.op = 'RENAME'
+ gp.oldpath = line[12:].rstrip()
+ elif line.startswith('rename to '):
+ gp.path = line[10:].rstrip()
+ elif line.startswith('copy from '):
+ gp.op = 'COPY'
+ gp.oldpath = line[10:].rstrip()
+ elif line.startswith('copy to '):
+ gp.path = line[8:].rstrip()
+ elif line.startswith('deleted file'):
+ gp.op = 'DELETE'
+ elif line.startswith('new file mode '):
+ gp.op = 'ADD'
+ gp.mode = int(line.rstrip()[-3:], 8)
+ elif line.startswith('new mode '):
+ gp.mode = int(line.rstrip()[-3:], 8)
+ if gp:
+ gitpatches.append(gp)
+
+ if not gitpatches:
+ dopatch = True
+
+ return (dopatch, gitpatches)
+
+def dogitpatch(patchname, gitpatches):
+ """Preprocess git patch so that vanilla patch can handle it"""
+ pf = file(patchname)
+ pfline = 1
+
+ fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
+ tmpfp = os.fdopen(fd, 'w')
+
+ try:
+ for i in range(len(gitpatches)):
+ p = gitpatches[i]
+ if not p.copymod:
+ continue
+
+ copyfile(p.oldpath, p.path)
+
+ # rewrite patch hunk
+ while pfline < p.lineno:
+ tmpfp.write(pf.readline())
+ pfline += 1
+ tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
+ line = pf.readline()
+ pfline += 1
+ while not line.startswith('--- a/'):
+ tmpfp.write(line)
+ line = pf.readline()
+ pfline += 1
+ tmpfp.write('--- a/%s\n' % p.path)
+
+ line = pf.readline()
+ while line:
+ tmpfp.write(line)
+ line = pf.readline()
+ except:
+ tmpfp.close()
+ os.unlink(patchname)
+ raise
+
+ tmpfp.close()
+ return patchname
+
+def patch(patchname, ui, strip=1, cwd=None):
+ """apply the patch <patchname> to the working directory.
+ a list of patched files is returned"""
+
+ (dopatch, gitpatches) = readgitpatch(patchname)
+
+ files = {}
+ fuzz = False
+ if dopatch:
+ if dopatch == 'filter':
+ patchname = dogitpatch(patchname, gitpatches)
+ patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
+ args = []
+ if cwd:
+ args.append('-d %s' % util.shellquote(cwd))
+ fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
+ util.shellquote(patchname)))
+
+ if dopatch == 'filter':
+ False and os.unlink(patchname)
+
+ for line in fp:
+ line = line.rstrip()
+ ui.note(line + '\n')
+ if line.startswith('patching file '):
+ pf = util.parse_patch_output(line)
+ printed_file = False
+ files.setdefault(pf, (None, None))
+ elif line.find('with fuzz') >= 0:
+ fuzz = True
+ if not printed_file:
+ ui.warn(pf + '\n')
+ printed_file = True
+ ui.warn(line + '\n')
+ elif line.find('saving rejects to file') >= 0:
+ ui.warn(line + '\n')
+ elif line.find('FAILED') >= 0:
+ if not printed_file:
+ ui.warn(pf + '\n')
+ printed_file = True
+ ui.warn(line + '\n')
+
+ code = fp.close()
+ if code:
+ raise util.Abort(_("patch command failed: %s") %
+ util.explain_exit(code)[0])
+
+ for gp in gitpatches:
+ files[gp.path] = (gp.op, gp)
+
+ return (files, fuzz)
+
+def diffopts(ui, opts={}):
+ return mdiff.diffopts(
+ text=opts.get('text'),
+ git=(opts.get('git') or
+ ui.configbool('diff', 'git', None)),
+ showfunc=(opts.get('show_function') or
+ ui.configbool('diff', 'showfunc', None)),
+ ignorews=(opts.get('ignore_all_space') or
+ ui.configbool('diff', 'ignorews', None)),
+ ignorewsamount=(opts.get('ignore_space_change') or
+ ui.configbool('diff', 'ignorewsamount', None)),
+ ignoreblanklines=(opts.get('ignore_blank_lines') or
+ ui.configbool('diff', 'ignoreblanklines', None)))
+
+def updatedir(ui, repo, patches, wlock=None):
+ '''Update dirstate after patch application according to metadata'''
+ if not patches:
+ return
+ copies = []
+ removes = []
+ cfiles = patches.keys()
+ copts = {'after': False, 'force': False}
+ cwd = repo.getcwd()
+ if cwd:
+ cfiles = [util.pathto(cwd, f) for f in patches.keys()]
+ for f in patches:
+ ctype, gp = patches[f]
+ if ctype == 'RENAME':
+ copies.append((gp.oldpath, gp.path, gp.copymod))
+ removes.append(gp.oldpath)
+ elif ctype == 'COPY':
+ copies.append((gp.oldpath, gp.path, gp.copymod))
+ elif ctype == 'DELETE':
+ removes.append(gp.path)
+ for src, dst, after in copies:
+ if not after:
+ copyfile(src, dst, repo.root)
+ repo.copy(src, dst, wlock=wlock)
+ if removes:
+ repo.remove(removes, True, wlock=wlock)
+ for f in patches:
+ ctype, gp = patches[f]
+ if gp and gp.mode:
+ x = gp.mode & 0100 != 0
+ dst = os.path.join(repo.root, gp.path)
+ util.set_exec(dst, x)
+ cmdutil.addremove(repo, cfiles, wlock=wlock)
+ files = patches.keys()
+ files.extend([r for r in removes if r not in files])
+ files.sort()
+
+ return files
+
+def diff(repo, node1=None, node2=None, files=None, match=util.always,
+ fp=None, changes=None, opts=None):
+ '''print diff of changes to files between two nodes, or node and
+ working directory.
+
+ if node1 is None, use first dirstate parent instead.
+ if node2 is None, compare node1 with working directory.'''
+
+ if opts is None:
+ opts = mdiff.defaultopts
+ if fp is None:
+ fp = repo.ui
+
+ if not node1:
+ node1 = repo.dirstate.parents()[0]
+
+ clcache = {}
+ def getchangelog(n):
+ if n not in clcache:
+ clcache[n] = repo.changelog.read(n)
+ return clcache[n]
+ mcache = {}
+ def getmanifest(n):
+ if n not in mcache:
+ mcache[n] = repo.manifest.read(n)
+ return mcache[n]
+ fcache = {}
+ def getfile(f):
+ if f not in fcache:
+ fcache[f] = repo.file(f)
+ return fcache[f]
+
+ # reading the data for node1 early allows it to play nicely
+ # with repo.status and the revlog cache.
+ change = getchangelog(node1)
+ mmap = getmanifest(change[0])
+ date1 = util.datestr(change[2])
+
+ if not changes:
+ changes = repo.status(node1, node2, files, match=match)[:5]
+ modified, added, removed, deleted, unknown = changes
+ if files:
+ def filterfiles(filters):
+ l = [x for x in filters if x in files]
+
+ for t in files:
+ if not t.endswith("/"):
+ t += "/"
+ l += [x for x in filters if x.startswith(t)]
+ return l
+
+ modified, added, removed = map(filterfiles, (modified, added, removed))
+
+ if not modified and not added and not removed:
+ return
+
+ def renamedbetween(f, n1, n2):
+ r1, r2 = map(repo.changelog.rev, (n1, n2))
+ src = None
+ while r2 > r1:
+ cl = getchangelog(n2)[0]
+ m = getmanifest(cl)
+ try:
+ src = getfile(f).renamed(m[f])
+ except KeyError:
+ return None
+ if src:
+ f = src[0]
+ n2 = repo.changelog.parents(n2)[0]
+ r2 = repo.changelog.rev(n2)
+ return src
+
+ if node2:
+ change = getchangelog(node2)
+ mmap2 = getmanifest(change[0])
+ _date2 = util.datestr(change[2])
+ def date2(f):
+ return _date2
+ def read(f):
+ return getfile(f).read(mmap2[f])
+ def renamed(f):
+ return renamedbetween(f, node1, node2)
+ else:
+ tz = util.makedate()[1]
+ _date2 = util.datestr()
+ def date2(f):
+ try:
+ return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz))
+ except OSError, err:
+ if err.errno != errno.ENOENT: raise
+ return _date2
+ def read(f):
+ return repo.wread(f)
+ def renamed(f):
+ src = repo.dirstate.copies.get(f)
+ parent = repo.dirstate.parents()[0]
+ if src:
+ f = src[0]
+ of = renamedbetween(f, node1, parent)
+ if of:
+ return of
+ elif src:
+ cl = getchangelog(parent)[0]
+ return (src, getmanifest(cl)[src])
+ else:
+ return None
+
+ if repo.ui.quiet:
+ r = None
+ else:
+ hexfunc = repo.ui.verbose and hex or short
+ r = [hexfunc(node) for node in [node1, node2] if node]
+
+ if opts.git:
+ copied = {}
+ for f in added:
+ src = renamed(f)
+ if src:
+ copied[f] = src
+ srcs = [x[1][0] for x in copied.items()]
+
+ all = modified + added + removed
+ all.sort()
+ for f in all:
+ to = None
+ tn = None
+ dodiff = True
+ if f in mmap:
+ to = getfile(f).read(mmap[f])
+ if f not in removed:
+ tn = read(f)
+ if opts.git:
+ def gitmode(x):
+ return x and '100755' or '100644'
+ def addmodehdr(header, omode, nmode):
+ if omode != nmode:
+ header.append('old mode %s\n' % omode)
+ header.append('new mode %s\n' % nmode)
+
+ a, b = f, f
+ header = []
+ if f in added:
+ if node2:
+ mode = gitmode(mmap2.execf(f))
+ else:
+ mode = gitmode(util.is_exec(repo.wjoin(f), None))
+ if f in copied:
+ a, arev = copied[f]
+ omode = gitmode(mmap.execf(a))
+ addmodehdr(header, omode, mode)
+ op = a in removed and 'rename' or 'copy'
+ header.append('%s from %s\n' % (op, a))
+ header.append('%s to %s\n' % (op, f))
+ to = getfile(a).read(arev)
+ else:
+ header.append('new file mode %s\n' % mode)
+ elif f in removed:
+ if f in srcs:
+ dodiff = False
+ else:
+ mode = gitmode(mmap.execf(f))
+ header.append('deleted file mode %s\n' % mode)
+ else:
+ omode = gitmode(mmap.execf(f))
+ nmode = gitmode(util.is_exec(repo.wjoin(f), mmap.execf(f)))
+ addmodehdr(header, omode, nmode)
+ r = None
+ if dodiff:
+ header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
+ fp.write(''.join(header))
+ if dodiff:
+ fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, opts=opts))
+
+def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
+ opts=None):
+ '''export changesets as hg patches.'''
+
+ total = len(revs)
+ revwidth = max(map(len, revs))
+
+ def single(node, seqno, fp):
+ parents = [p for p in repo.changelog.parents(node) if p != nullid]
+ if switch_parent:
+ parents.reverse()
+ prev = (parents and parents[0]) or nullid
+ change = repo.changelog.read(node)
+
+ if not fp:
+ fp = cmdutil.make_file(repo, template, node, total=total,
+ seqno=seqno, revwidth=revwidth)
+ if fp not in (sys.stdout, repo.ui):
+ repo.ui.note("%s\n" % fp.name)
+
+ fp.write("# HG changeset patch\n")
+ fp.write("# User %s\n" % change[1])
+ fp.write("# Date %d %d\n" % change[2])
+ fp.write("# Node ID %s\n" % hex(node))
+ fp.write("# Parent %s\n" % hex(prev))
+ if len(parents) > 1:
+ fp.write("# Parent %s\n" % hex(parents[1]))
+ fp.write(change[4].rstrip())
+ fp.write("\n\n")
+
+ diff(repo, prev, node, fp=fp, opts=opts)
+ if fp not in (sys.stdout, repo.ui):
+ fp.close()
+
+ for seqno, cset in enumerate(revs):
+ single(cset, seqno, fp)
--- a/mercurial/remoterepo.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/remoterepo.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
-# remoterepo - remote repositort proxy classes for mercurial
+# remoterepo - remote repository proxy classes for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/repo.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/repo.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,7 @@
# repo.py - repository base classes for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/revlog.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/revlog.py Tue Aug 22 07:55:10 2006 -0700
@@ -4,7 +4,7 @@
This provides efficient delta storage with O(1) retrieve and append
and O(changes) merge between branches
-Copyright 2005 Matt Mackall <mpm@selenic.com>
+Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
@@ -766,6 +766,19 @@
raise RevlogError(_("No match found"))
+ def cmp(self, node, text):
+ """compare text with a given file revision"""
+ p1, p2 = self.parents(node)
+ return hash(text, p1, p2) != node
+
+ def makenode(self, node, text):
+ """calculate a file nodeid for text, descended or possibly
+ unchanged from node"""
+
+ if self.cmp(node, text):
+ return hash(text, node, nullid)
+ return node
+
def diff(self, a, b):
"""return a delta between two revisions"""
return mdiff.textdiff(a, b)
--- a/mercurial/sshrepo.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/sshrepo.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
# sshrepo.py - ssh repository proxy class for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/sshserver.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/sshserver.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,7 @@
# sshserver.py - ssh protocol server support for mercurial
#
# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/statichttprepo.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/statichttprepo.py Tue Aug 22 07:55:10 2006 -0700
@@ -2,7 +2,7 @@
#
# This provides read-only repo access to repositories exported via static http
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/strutil.py Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,34 @@
+# strutil.py - string utilities for Mercurial
+#
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+def findall(haystack, needle, start=0, end=None):
+ if end is None:
+ end = len(haystack)
+ if end < 0:
+ end += len(haystack)
+ if start < 0:
+ start += len(haystack)
+ while start < end:
+ c = haystack.find(needle, start, end)
+ if c == -1:
+ break
+ yield c
+ start = c + 1
+
+def rfindall(haystack, needle, start=0, end=None):
+ if end is None:
+ end = len(haystack)
+ if end < 0:
+ end += len(haystack)
+ if start < 0:
+ start += len(haystack)
+ while end >= 0:
+ c = haystack.rfind(needle, start, end)
+ if c == -1:
+ break
+ yield c
+ end = c - 1
--- a/mercurial/templater.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/templater.py Tue Aug 22 07:55:10 2006 -0700
@@ -459,7 +459,7 @@
yield x
if self.ui.debugflag:
- files = self.repo.changes(log.parents(changenode)[0], changenode)
+ files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
def showfiles(**args):
for x in showlist('file', files[0], **args): yield x
def showadds(**args):
--- a/mercurial/transaction.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/transaction.py Tue Aug 22 07:55:10 2006 -0700
@@ -6,7 +6,7 @@
# effectively log-structured, this should amount to simply truncating
# anything that isn't referenced in the changelog.
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
--- a/mercurial/ui.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/ui.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,22 +1,24 @@
# ui.py - user interface bits for mercurial
#
-# Copyright 2005 Matt Mackall <mpm@selenic.com>
+# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
from i18n import gettext as _
from demandload import *
-demandload(globals(), "errno getpass os re smtplib socket sys tempfile")
-demandload(globals(), "ConfigParser templater traceback util")
+demandload(globals(), "errno getpass os re socket sys tempfile")
+demandload(globals(), "ConfigParser mdiff templater traceback util")
class ui(object):
def __init__(self, verbose=False, debug=False, quiet=False,
- interactive=True, traceback=False, parentui=None):
+ interactive=True, traceback=False, parentui=None,
+ readhooks=[]):
self.overlay = {}
if parentui is None:
# this is the parent of all ui children
self.parentui = None
+ self.readhooks = list(readhooks)
self.cdata = ConfigParser.SafeConfigParser()
self.readconfig(util.rcpath())
@@ -34,6 +36,7 @@
else:
# parentui may point to an ui object which is already a child
self.parentui = parentui.parentui or parentui
+ self.readhooks = list(parentui.readhooks or readhooks)
parent_cdata = self.parentui.cdata
self.cdata = ConfigParser.SafeConfigParser(parent_cdata.defaults())
# make interpolation work
@@ -78,6 +81,8 @@
for name, path in self.configitems("paths"):
if path and "://" not in path and not os.path.isabs(path):
self.cdata.set("paths", name, os.path.join(root, path))
+ for hook in self.readhooks:
+ hook(self)
def setconfig(self, section, name, val):
self.overlay[(section, name)] = val
@@ -169,17 +174,6 @@
result[key.lower()] = value
return result
- def diffopts(self):
- if self.diffcache:
- return self.diffcache
- result = {'showfunc': True, 'ignorews': False,
- 'ignorewsamount': False, 'ignoreblanklines': False}
- for key, value in self.configitems("diff"):
- if value:
- result[key.lower()] = (value.lower() == 'true')
- self.diffcache = result
- return result
-
def username(self):
"""Return default username to be used in commits.
@@ -292,62 +286,6 @@
return t
- def sendmail(self):
- '''send mail message. object returned has one method, sendmail.
- call as sendmail(sender, list-of-recipients, msg).'''
-
- def smtp():
- '''send mail using smtp.'''
-
- local_hostname = self.config('smtp', 'local_hostname')
- s = smtplib.SMTP(local_hostname=local_hostname)
- mailhost = self.config('smtp', 'host')
- if not mailhost:
- raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
- mailport = int(self.config('smtp', 'port', 25))
- self.note(_('sending mail: smtp host %s, port %s\n') %
- (mailhost, mailport))
- s.connect(host=mailhost, port=mailport)
- if self.configbool('smtp', 'tls'):
- self.note(_('(using tls)\n'))
- s.ehlo()
- s.starttls()
- s.ehlo()
- username = self.config('smtp', 'username')
- password = self.config('smtp', 'password')
- if username and password:
- self.note(_('(authenticating to mail server as %s)\n') %
- (username))
- s.login(username, password)
- return s
-
- class sendmail(object):
- '''send mail using sendmail.'''
-
- def __init__(self, ui, program):
- self.ui = ui
- self.program = program
-
- def sendmail(self, sender, recipients, msg):
- cmdline = '%s -f %s %s' % (
- self.program, templater.email(sender),
- ' '.join(map(templater.email, recipients)))
- self.ui.note(_('sending mail: %s\n') % cmdline)
- fp = os.popen(cmdline, 'w')
- fp.write(msg)
- ret = fp.close()
- if ret:
- raise util.Abort('%s %s' % (
- os.path.basename(self.program.split(None, 1)[0]),
- util.explain_exit(ret)[0]))
-
- method = self.config('email', 'method', 'smtp')
- if method == 'smtp':
- mail = smtp()
- else:
- mail = sendmail(self, method)
- return mail
-
def print_exc(self):
'''print exception traceback if traceback printing enabled.
only to call in exception handler. returns true if traceback
--- a/mercurial/util.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/util.py Tue Aug 22 07:55:10 2006 -0700
@@ -2,6 +2,8 @@
util.py - Mercurial utility functions and platform specfic implementations
Copyright 2005 K. Thananchayan <thananck@yahoo.com>
+ Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
+ Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
@@ -93,27 +95,6 @@
return p_name
return default
-def patch(strip, patchname, ui, cwd=None):
- """apply the patch <patchname> to the working directory.
- a list of patched files is returned"""
- patcher = find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
- args = []
- if cwd:
- args.append('-d %s' % shellquote(cwd))
- fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
- shellquote(patchname)))
- files = {}
- for line in fp:
- line = line.rstrip()
- ui.status("%s\n" % line)
- if line.startswith('patching file '):
- pf = parse_patch_output(line)
- files.setdefault(pf, 1)
- code = fp.close()
- if code:
- raise Abort(_("patch command failed: %s") % explain_exit(code)[0])
- return files.keys()
-
def binary(s):
"""return true if a string is binary data using diff's heuristic"""
if s and '\0' in s[:4096]:
--- a/mercurial/version.py Thu Aug 10 16:59:58 2006 +0200
+++ b/mercurial/version.py Tue Aug 22 07:55:10 2006 -0700
@@ -1,4 +1,4 @@
-# Copyright (C) 2005 by Intevation GmbH
+# Copyright (C) 2005, 2006 by Intevation GmbH
# Author(s):
# Thomas Arendsen Hein <thomas@intevation.de>
#
--- a/tests/README Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/README Tue Aug 22 07:55:10 2006 -0700
@@ -28,6 +28,68 @@
- diff will show the current time
- use hg diff | sed "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" to strip
- dates
+ use hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+ to strip dates
+
+- You can append your own hgrc settings to the file that the environment
+ variable HGRCPATH points to. This file is cleared before running a test.
+
+You also need to be careful that the tests are portable from one platform
+to another. You're probably working on Linux, where the GNU toolchain has
+more (or different) functionality than on MacOS, *BSD, Solaris, AIX, etc.
+While testing on all platforms is the only sure-fire way to make sure that
+you've written portable code, here's a list of problems that have been
+found and fixed in the tests. Another, more comprehensive list may be
+found in the GNU Autoconf manual, online here:
+
+ http://www.gnu.org/software/autoconf/manual/html_node/Portable-Shell.html
+
+sh:
+
+The Bourne shell is a very basic shell. /bin/sh on Linux is typically
+bash, which even in Bourne-shell mode has many features that Bourne shells
+on other Unix systems don't have (and even on Linux /bin/sh isn't
+guaranteed to be bash). You'll need to be careful about constructs that
+seem ubiquitous, but are actually not available in the least common
+denominator. While using another shell (ksh, bash explicitly, posix shell,
+etc.) explicitly may seem like another option, these may not exist in a
+portable location, and so are generally probably not a good idea. You may
+find that rewriting the test in python will be easier.
+
+- don't use pushd/popd; save the output of "pwd" and use "cd" in place of
+ the pushd, and cd back to the saved pwd instead of popd.
+- don't use math expressions like let, (( ... )), or $(( ... )); use "expr"
+ instead.
+
+grep:
+
+- don't use the -q option; redirect stdout to /dev/null instead.
+
+- don't use extended regular expressions with grep; use egrep instead, and
+ don't escape any regex operators.
+
+sed:
+
+- make sure that the beginning-of-line matcher ("^") is at the very
+ beginning of the expression -- it may not be supported inside parens.
+
+echo:
+
+- echo may interpret "\n" and print a newline; use printf instead if you
+ want a literal "\n" (backslash + n).
+
+false:
+
+- false is guaranteed only to return a non-zero value; you cannot depend on
+ it being 1. On Solaris in particular, /bin/false returns 255. Rewrite
+ your test to not depend on a particular return value, or create a
+ temporary "false" executable, and call that instead.
+
+diff:
+
+- don't use the -N option. There's no particularly good workaround short
+ of writing a reasonably complicated replacement script, but substituting
+ gdiff for diff if you can't rewrite the test not to need -N will probably
+ do.
--- a/tests/run-tests.py Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/run-tests.py Tue Aug 22 07:55:10 2006 -0700
@@ -211,6 +211,10 @@
sys.stdout.write('.')
sys.stdout.flush()
+ # create a fresh hgrc
+ hgrc = file(HGRCPATH, 'w+')
+ hgrc.close()
+
err = os.path.join(TESTDIR, test+".err")
ref = os.path.join(TESTDIR, test+".out")
@@ -319,11 +323,11 @@
os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"'
os.environ["HGUSER"] = "test"
-os.environ["HGRCPATH"] = ""
TESTDIR = os.environ["TESTDIR"] = os.getcwd()
HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
+HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
vlog("# Using TESTDIR", TESTDIR)
vlog("# Using HGTMP", HGTMP)
--- a/tests/test-abort-checkin Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-abort-checkin Tue Aug 22 07:55:10 2006 -0700
@@ -1,8 +1,12 @@
#!/bin/sh
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
+cat > $HGTMP/false <<EOF
+#!/bin/sh
+exit 1
+EOF
+chmod +x $HGTMP/false
hg init foo
cd foo
@@ -11,7 +15,7 @@
# mq may keep a reference to the repository so __del__ will not be called
# and .hg/journal.dirstate will not be deleted:
-HGEDITOR=false hg ci
-HGEDITOR=false hg ci
+HGEDITOR=$HGTMP/false hg ci
+HGEDITOR=$HGTMP/false hg ci
exit 0
--- a/tests/test-addremove Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-addremove Tue Aug 22 07:55:10 2006 -0700
@@ -10,3 +10,17 @@
touch ../foo_2 bar_2
hg -v addremove
hg -v commit -m "add 2" -d "1000000 0"
+
+cd ..
+hg init sim
+cd sim
+echo a > a
+echo a >> a
+echo a >> a
+echo c > c
+hg commit -Ama
+mv a b
+rm c
+echo d > d
+hg addremove -s 0.5
+hg commit -mb
--- a/tests/test-addremove.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-addremove.out Tue Aug 22 07:55:10 2006 -0700
@@ -1,10 +1,15 @@
-(the addremove command is deprecated; use add and remove --after instead)
adding dir/bar
adding foo
dir/bar
foo
-(the addremove command is deprecated; use add and remove --after instead)
adding dir/bar_2
adding foo_2
dir/bar_2
foo_2
+adding a
+adding c
+adding b
+adding d
+removing a
+removing c
+recording removal of a as rename to b (100% similar)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-annotate Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+echo % init
+hg init
+
+echo % commit
+echo 'a' > a
+hg ci -A -m test -u nobody -d '1 0'
+
+echo % annotate -c
+hg annotate -c a
+
+echo % annotate -d
+hg annotate -d a
+
+echo % annotate -n
+hg annotate -n a
+
+echo % annotate -u
+hg annotate -u a
+
+echo % annotate -cdnu
+hg annotate -cdnu a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-annotate.out Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,13 @@
+% init
+% commit
+adding a
+% annotate -c
+8435f90966e4: a
+% annotate -d
+Thu Jan 01 00:00:01 1970 +0000: a
+% annotate -n
+0: a
+% annotate -u
+nobody: a
+% annotate -cdnu
+nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
--- a/tests/test-archive.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-archive.out Tue Aug 22 07:55:10 2006 -0700
@@ -1,8 +1,5 @@
-(the addremove command is deprecated; use add and remove --after instead)
adding foo
-(the addremove command is deprecated; use add and remove --after instead)
adding bar
-(the addremove command is deprecated; use add and remove --after instead)
adding baz/bletch
test-archive-TIP/.hg_archival.txt
test-archive-TIP/bar
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-bisect Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+set -e
+
+echo "[extensions]" >> $HGRCPATH
+echo "hbisect=" >> $HGRCPATH
+
+echo % init
+hg init
+
+echo % committing changes
+count=0
+echo > a
+while test $count -lt 32 ; do
+ echo 'a' >> a
+ test $count -eq 0 && hg add
+ hg ci -m "msg $count" -d "$count 0"
+ echo % committed changeset $count
+ count=`expr $count + 1`
+done
+
+echo % log
+hg log
+
+echo % hg up -C
+hg up -C
+
+echo % bisect test
+hg bisect init
+hg bisect bad
+hg bisect good 1
+hg bisect good
+hg bisect good
+hg bisect good
+hg bisect bad
+hg bisect good
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-bisect.out Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,216 @@
+% init
+% committing changes
+adding a
+% committed changeset 0
+% committed changeset 1
+% committed changeset 2
+% committed changeset 3
+% committed changeset 4
+% committed changeset 5
+% committed changeset 6
+% committed changeset 7
+% committed changeset 8
+% committed changeset 9
+% committed changeset 10
+% committed changeset 11
+% committed changeset 12
+% committed changeset 13
+% committed changeset 14
+% committed changeset 15
+% committed changeset 16
+% committed changeset 17
+% committed changeset 18
+% committed changeset 19
+% committed changeset 20
+% committed changeset 21
+% committed changeset 22
+% committed changeset 23
+% committed changeset 24
+% committed changeset 25
+% committed changeset 26
+% committed changeset 27
+% committed changeset 28
+% committed changeset 29
+% committed changeset 30
+% committed changeset 31
+% log
+changeset: 31:58c80a7c8a40
+tag: tip
+user: test
+date: Thu Jan 01 00:00:31 1970 +0000
+summary: msg 31
+
+changeset: 30:ed2d2f24b11c
+user: test
+date: Thu Jan 01 00:00:30 1970 +0000
+summary: msg 30
+
+changeset: 29:b5bd63375ab9
+user: test
+date: Thu Jan 01 00:00:29 1970 +0000
+summary: msg 29
+
+changeset: 28:8e0c2264c8af
+user: test
+date: Thu Jan 01 00:00:28 1970 +0000
+summary: msg 28
+
+changeset: 27:288867a866e9
+user: test
+date: Thu Jan 01 00:00:27 1970 +0000
+summary: msg 27
+
+changeset: 26:3efc6fd51aeb
+user: test
+date: Thu Jan 01 00:00:26 1970 +0000
+summary: msg 26
+
+changeset: 25:02a84173a97a
+user: test
+date: Thu Jan 01 00:00:25 1970 +0000
+summary: msg 25
+
+changeset: 24:10e0acd3809e
+user: test
+date: Thu Jan 01 00:00:24 1970 +0000
+summary: msg 24
+
+changeset: 23:5ec79163bff4
+user: test
+date: Thu Jan 01 00:00:23 1970 +0000
+summary: msg 23
+
+changeset: 22:06c7993750ce
+user: test
+date: Thu Jan 01 00:00:22 1970 +0000
+summary: msg 22
+
+changeset: 21:e5db6aa3fe2a
+user: test
+date: Thu Jan 01 00:00:21 1970 +0000
+summary: msg 21
+
+changeset: 20:7128fb4fdbc9
+user: test
+date: Thu Jan 01 00:00:20 1970 +0000
+summary: msg 20
+
+changeset: 19:52798545b482
+user: test
+date: Thu Jan 01 00:00:19 1970 +0000
+summary: msg 19
+
+changeset: 18:86977a90077e
+user: test
+date: Thu Jan 01 00:00:18 1970 +0000
+summary: msg 18
+
+changeset: 17:03515f4a9080
+user: test
+date: Thu Jan 01 00:00:17 1970 +0000
+summary: msg 17
+
+changeset: 16:a2e6ea4973e9
+user: test
+date: Thu Jan 01 00:00:16 1970 +0000
+summary: msg 16
+
+changeset: 15:e7fa0811edb0
+user: test
+date: Thu Jan 01 00:00:15 1970 +0000
+summary: msg 15
+
+changeset: 14:ce8f0998e922
+user: test
+date: Thu Jan 01 00:00:14 1970 +0000
+summary: msg 14
+
+changeset: 13:9d7d07bc967c
+user: test
+date: Thu Jan 01 00:00:13 1970 +0000
+summary: msg 13
+
+changeset: 12:1941b52820a5
+user: test
+date: Thu Jan 01 00:00:12 1970 +0000
+summary: msg 12
+
+changeset: 11:7b4cd9578619
+user: test
+date: Thu Jan 01 00:00:11 1970 +0000
+summary: msg 11
+
+changeset: 10:7c5eff49a6b6
+user: test
+date: Thu Jan 01 00:00:10 1970 +0000
+summary: msg 10
+
+changeset: 9:eb44510ef29a
+user: test
+date: Thu Jan 01 00:00:09 1970 +0000
+summary: msg 9
+
+changeset: 8:453eb4dba229
+user: test
+date: Thu Jan 01 00:00:08 1970 +0000
+summary: msg 8
+
+changeset: 7:03750880c6b5
+user: test
+date: Thu Jan 01 00:00:07 1970 +0000
+summary: msg 7
+
+changeset: 6:a3d5c6fdf0d3
+user: test
+date: Thu Jan 01 00:00:06 1970 +0000
+summary: msg 6
+
+changeset: 5:7874a09ea728
+user: test
+date: Thu Jan 01 00:00:05 1970 +0000
+summary: msg 5
+
+changeset: 4:9b2ba8336a65
+user: test
+date: Thu Jan 01 00:00:04 1970 +0000
+summary: msg 4
+
+changeset: 3:b53bea5e2fcb
+user: test
+date: Thu Jan 01 00:00:03 1970 +0000
+summary: msg 3
+
+changeset: 2:db07c04beaca
+user: test
+date: Thu Jan 01 00:00:02 1970 +0000
+summary: msg 2
+
+changeset: 1:5cd978ea5149
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: msg 1
+
+changeset: 0:b99c7b9c8e11
+user: test
+date: Thu Jan 01 00:00:00 1970 +0000
+summary: msg 0
+
+% hg up -C
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% bisect test
+Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+Testing changeset 23:5ec79163bff4 (15 changesets remaining, ~3 tests)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+Testing changeset 27:288867a866e9 (8 changesets remaining, ~3 tests)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+Testing changeset 29:b5bd63375ab9 (4 changesets remaining, ~2 tests)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+Testing changeset 28:8e0c2264c8af (2 changesets remaining, ~1 tests)
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+The first bad revision is:
+changeset: 29:b5bd63375ab9
+user: test
+date: Thu Jan 01 00:00:29 1970 +0000
+summary: msg 29
+
--- a/tests/test-command-template.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-command-template.out Tue Aug 22 07:55:10 2006 -0700
@@ -1,4 +1,20 @@
# default style is like normal output
+1c1
+< changeset: 3:10e46f2dcbf4
+---
+> changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
+10c10
+< changeset: 2:97054abb4ab8
+---
+> changeset: 2:97054abb4ab824450e9164180baf491ae0078465
+18c18
+< changeset: 1:b608e9d1a3f0
+---
+> changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
+29c29
+< changeset: 0:1e4e1b8f71e0
+---
+> changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
18a19
> files:
29a31
--- a/tests/test-confused-revert Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-confused-revert Tue Aug 22 07:55:10 2006 -0700
@@ -13,7 +13,7 @@
hg status
echo "reverting..."
-hg revert
+hg revert --all
echo "%%% should show b unknown and a back to normal"
hg status
@@ -42,10 +42,10 @@
hg status
echo "%%% revert should fail"
-hg revert
+hg revert --all
echo "%%% revert should be ok now"
-hg revert -r2
+hg revert -r2 --all
echo "%%% should show b unknown and a marked modified (merged)"
hg status
--- a/tests/test-copy.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-copy.out Tue Aug 22 07:55:10 2006 -0700
@@ -2,7 +2,7 @@
b
b: copy a:b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
we should see two history entries
-changeset: 1:386a3cc01532710ca78aed9a54fa2f459c04f29c
+changeset: 1:386a3cc01532
tag: tip
user: test
date: Mon Jan 12 13:46:40 1970 +0000
@@ -11,7 +11,7 @@
2
-changeset: 0:33aaa84a386bd609094aeb21a97c09436c482ef1
+changeset: 0:33aaa84a386b
user: test
date: Mon Jan 12 13:46:40 1970 +0000
files: a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diff-subdir Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+hg init
+
+mkdir alpha
+touch alpha/one
+mkdir beta
+touch beta/two
+
+hg add alpha/one beta/two
+hg ci -m "start" -d "1000000 0"
+
+echo 1 > alpha/one
+echo 2 > beta/two
+
+echo EVERYTHING
+hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo BETA ONLY
+hg diff beta | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo INSIDE BETA
+cd beta
+hg diff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diff-subdir.out Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,23 @@
+EVERYTHING
+diff -r ec612a6291f1 alpha/one
+--- a/alpha/one
++++ b/alpha/one
+@@ -0,0 +1,1 @@
++1
+diff -r ec612a6291f1 beta/two
+--- a/beta/two
++++ b/beta/two
+@@ -0,0 +1,1 @@
++2
+BETA ONLY
+diff -r ec612a6291f1 beta/two
+--- a/beta/two
++++ b/beta/two
+@@ -0,0 +1,1 @@
++2
+INSIDE BETA
+diff -r ec612a6291f1 beta/two
+--- a/beta/two
++++ b/beta/two
+@@ -0,0 +1,1 @@
++2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-extdiff Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+echo "[extensions]" >> $HGRCPATH
+echo "extdiff=" >> $HGRCPATH
+
+hg init a
+cd a
+echo a > a
+hg add
+diff -N /dev/null /dev/null 2> /dev/null
+if [ $? -ne 0 ]; then
+ opt="-p gdiff"
+fi
+hg extdiff -o -Nr $opt
+
+echo "[extdiff]" >> $HGRCPATH
+echo "cmd.falabala=echo" >> $HGRCPATH
+echo "opts.falabala=diffing" >> $HGRCPATH
+
+hg falabala
+
+hg help falabala
+
+hg ci -d '0 0' -mtest1
+
+echo b >> a
+hg ci -d '1 0' -mtest2
+
+hg falabala -r 0:1 || echo "diff-like tools yield a non-zero exit code"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-extdiff.out Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,32 @@
+adding a
+making snapshot of 0 files from rev 000000000000
+making snapshot of 1 files from working dir
+diff -Nr a.000000000000/a a/a
+0a1
+> a
+making snapshot of 0 files from rev 000000000000
+making snapshot of 1 files from working dir
+diffing a.000000000000 a
+hg falabala [OPT]... [FILE]...
+
+use 'echo' to diff repository (or selected files)
+
+ Show differences between revisions for the specified
+ files, using the 'echo' program.
+
+ When two revision arguments are given, then changes are
+ shown between those revisions. If only one revision is
+ specified then that revision is compared to the working
+ directory, and, when no revisions are specified, the
+ working directory files are compared to its parent.
+
+options:
+
+ -o --option pass option to comparison program
+ -r --rev revision
+ -I --include include names matching the given patterns
+ -X --exclude exclude names matching the given patterns
+making snapshot of 1 files from rev e27a2475d60a
+making snapshot of 1 files from rev 5e49ec8d3f05
+diffing a.e27a2475d60a a.5e49ec8d3f05
+diff-like tools yield a non-zero exit code
--- a/tests/test-fetch Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-fetch Tue Aug 22 07:55:10 2006 -0700
@@ -1,8 +1,7 @@
#!/bin/sh
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "fetch=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "fetch=" >> $HGRCPATH
hg init a
echo a > a/a
--- a/tests/test-filebranch.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-filebranch.out Tue Aug 22 07:55:10 2006 -0700
@@ -31,10 +31,10 @@
2 150 71 2 2 a6aef98656b7 c36078bec30d 000000000000
3 221 72 3 3 0c2cc6fc80e2 182b283965f1 a6aef98656b7
log should show foo and quux changed
-changeset: 3:0c2cc6fc80e2d4ee289bb658dbbe9ad932380fe9
+changeset: 3:0c2cc6fc80e2
tag: tip
-parent: 1:182b283965f1069c0112784e30e7755ad1c0dd52
-parent: 2:a6aef98656b71154cae9d87408abe6d0218c8045
+parent: 1:182b283965f1
+parent: 2:a6aef98656b7
user: test
date: Mon Jan 12 13:46:40 1970 +0000
files: foo quux
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-git-export Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+hg init a
+cd a
+
+echo start > start
+hg ci -Amstart -d '0 0'
+echo new > new
+hg ci -Amnew -d '0 0'
+echo '% new file'
+hg diff --git -r 0 | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+hg cp new copy
+hg ci -mcopy -d '0 0'
+echo '% copy'
+hg diff --git -r 1:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+hg mv copy rename
+hg ci -mrename -d '0 0'
+echo '% rename'
+hg diff --git -r 2:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+hg rm rename
+hg ci -mdelete -d '0 0'
+echo '% delete'
+hg diff --git -r 3:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+cat > src <<EOF
+1
+2
+3
+4
+5
+EOF
+hg ci -Amsrc -d '0 0'
+chmod +x src
+hg ci -munexec -d '0 0'
+echo '% chmod 644'
+hg diff --git -r 5:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+hg mv src dst
+chmod -x dst
+echo a >> dst
+hg ci -mrenamemod -d '0 0'
+echo '% rename+mod+chmod'
+hg diff --git -r 6:tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-git-export.out Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,42 @@
+adding start
+adding new
+% new file
+diff --git a/new b/new
+new file mode 100644
+--- /dev/null
++++ b/new
+@@ -0,0 +1,1 @@
++new
+% copy
+diff --git a/new b/copy
+copy from new
+copy to copy
+% rename
+diff --git a/copy b/rename
+rename from copy
+rename to rename
+% delete
+diff --git a/rename b/rename
+deleted file mode 100644
+--- a/rename
++++ /dev/null
+@@ -1,1 +0,0 @@
+-new
+adding src
+% chmod 644
+diff --git a/src b/src
+old mode 100644
+new mode 100755
+% rename+mod+chmod
+diff --git a/src b/dst
+old mode 100755
+new mode 100644
+rename from src
+rename to dst
+--- a/dst
++++ b/dst
+@@ -3,3 +3,4 @@ 3
+ 3
+ 4
+ 5
++a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-git-import Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,122 @@
+#!/bin/sh
+
+hg init a
+cd a
+
+echo % new file
+hg import -mnew - <<EOF
+diff --git a/new b/new
+new file mode 100644
+index 0000000..7898192
+--- /dev/null
++++ b/new
+@@ -0,0 +1 @@
++a
+EOF
+
+echo % chmod +x
+hg import -msetx - <<EOF
+diff --git a/new b/new
+old mode 100644
+new mode 100755
+EOF
+
+test -x new || echo failed
+
+echo % copy
+hg import -mcopy - <<EOF
+diff --git a/new b/copy
+old mode 100755
+new mode 100644
+similarity index 100%
+copy from new
+copy to copy
+diff --git a/new b/copyx
+similarity index 100%
+copy from new
+copy to copyx
+EOF
+
+test -f copy -a ! -x copy || echo failed
+test -x copyx || echo failed
+cat copy
+hg cat copy
+
+echo % rename
+hg import -mrename - <<EOF
+diff --git a/copy b/rename
+similarity index 100%
+rename from copy
+rename to rename
+EOF
+
+hg locate
+
+echo % delete
+hg import -mdelete - <<EOF
+diff --git a/copyx b/copyx
+deleted file mode 100755
+index 7898192..0000000
+--- a/copyx
++++ /dev/null
+@@ -1 +0,0 @@
+-a
+EOF
+
+hg locate
+test -f copyx && echo failed || true
+
+echo % regular diff
+hg import -mregular - <<EOF
+diff --git a/rename b/rename
+index 7898192..72e1fe3 100644
+--- a/rename
++++ b/rename
+@@ -1 +1,5 @@
+ a
++a
++a
++a
++a
+EOF
+
+echo % copy and modify
+hg import -mcopymod - <<EOF
+diff --git a/rename b/copy2
+similarity index 80%
+copy from rename
+copy to copy2
+index 72e1fe3..b53c148 100644
+--- a/rename
++++ b/copy2
+@@ -1,5 +1,5 @@
+ a
+ a
+-a
++b
+ a
+ a
+EOF
+
+hg cat copy2
+
+echo % rename and modify
+hg import -mrenamemod - <<EOF
+diff --git a/copy2 b/rename2
+similarity index 80%
+rename from copy2
+rename to rename2
+index b53c148..8f81e29 100644
+--- a/copy2
++++ b/rename2
+@@ -1,5 +1,5 @@
+ a
+ a
+ b
+-a
++c
+ a
+EOF
+
+hg locate copy2
+hg cat rename2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-git-import.out Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,34 @@
+% new file
+applying patch from stdin
+% chmod +x
+applying patch from stdin
+% copy
+applying patch from stdin
+a
+a
+% rename
+applying patch from stdin
+copyx
+new
+rename
+% delete
+applying patch from stdin
+new
+rename
+% regular diff
+applying patch from stdin
+% copy and modify
+applying patch from stdin
+a
+a
+b
+a
+a
+% rename and modify
+applying patch from stdin
+copy2: No such file or directory
+a
+a
+b
+c
+a
--- a/tests/test-globalopts Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-globalopts Tue Aug 22 07:55:10 2006 -0700
@@ -45,7 +45,7 @@
hg --cwd b tip --verbose
echo %% --config
-hg --cwd c --config paths.quuxfoo=bar paths | grep -q quuxfoo && echo quuxfoo
+hg --cwd c --config paths.quuxfoo=bar paths | grep quuxfoo > /dev/null && echo quuxfoo
hg --cwd c --config '' tip -q
hg --cwd c --config a.b tip -q
hg --cwd c --config a tip -q
--- a/tests/test-globalopts.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-globalopts.out Tue Aug 22 07:55:10 2006 -0700
@@ -47,7 +47,7 @@
0:8580ff50825a
1:b6c483daf290
%% -v/--verbose
-changeset: 1:b6c483daf2907ce5825c0bb50f5716226281cc1a
+changeset: 1:b6c483daf290
tag: tip
user: test
date: Thu Jan 01 00:00:01 1970 +0000
@@ -56,7 +56,7 @@
b
-changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
+changeset: 0:8580ff50825a
user: test
date: Thu Jan 01 00:00:01 1970 +0000
files: a
@@ -64,7 +64,7 @@
a
-changeset: 0:b6c483daf2907ce5825c0bb50f5716226281cc1a
+changeset: 0:b6c483daf290
tag: tip
user: test
date: Thu Jan 01 00:00:01 1970 +0000
@@ -114,92 +114,94 @@
list of commands (use "hg help -v" to show aliases and global options):
- add add the specified files on the next commit
- annotate show changeset information per file line
- archive create unversioned archive of a repository revision
- backout reverse effect of earlier changeset
- bundle create a changegroup file
- cat output the latest or given revisions of files
- clone make a copy of an existing repository
- commit commit the specified files or all outstanding changes
- copy mark files as copied for the next commit
- diff diff repository (or selected files)
- export dump the header and diffs for one or more changesets
- grep search for a pattern in specified files and revisions
- heads show current repository heads
- help show help for a command, extension, or list of commands
- identify print information about the working copy
- import import an ordered set of patches
- incoming show new changesets found in source
- init create a new repository in the given directory
- locate locate files matching specific patterns
- log show revision history of entire repository or files
- manifest output the latest or given revision of the project manifest
- merge Merge working directory with another revision
- outgoing show changesets not found in destination
- parents show the parents of the working dir or revision
- paths show definition of symbolic path names
- pull pull changes from the specified source
- push push changes to the specified destination
- recover roll back an interrupted transaction
- remove remove the specified files on the next commit
- rename rename files; equivalent of copy + remove
- revert revert files or dirs to their states as of some revision
- rollback roll back the last transaction in this repository
- root print the root (top) of the current working dir
- serve export the repository via HTTP
- status show changed files in the working directory
- tag add a tag for the current tip or a given revision
- tags list repository tags
- tip show the tip revision
- unbundle apply a changegroup file
- update update or merge working directory
- verify verify the integrity of the repository
- version output version and copyright information
+ add add the specified files on the next commit
+ addremove add all new files, delete all missing files (DEPRECATED)
+ annotate show changeset information per file line
+ archive create unversioned archive of a repository revision
+ backout reverse effect of earlier changeset
+ bundle create a changegroup file
+ cat output the latest or given revisions of files
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ copy mark files as copied for the next commit
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ grep search for a pattern in specified files and revisions
+ heads show current repository heads
+ help show help for a command, extension, or list of commands
+ identify print information about the working copy
+ import import an ordered set of patches
+ incoming show new changesets found in source
+ init create a new repository in the given directory
+ locate locate files matching specific patterns
+ log show revision history of entire repository or files
+ manifest output the latest or given revision of the project manifest
+ merge Merge working directory with another revision
+ outgoing show changesets not found in destination
+ parents show the parents of the working dir or revision
+ paths show definition of symbolic path names
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ recover roll back an interrupted transaction
+ remove remove the specified files on the next commit
+ rename rename files; equivalent of copy + remove
+ revert revert files or dirs to their states as of some revision
+ rollback roll back the last transaction in this repository
+ root print the root (top) of the current working dir
+ serve export the repository via HTTP
+ status show changed files in the working directory
+ tag add a tag for the current tip or a given revision
+ tags list repository tags
+ tip show the tip revision
+ unbundle apply a changegroup file
+ update update or merge working directory
+ verify verify the integrity of the repository
+ version output version and copyright information
Mercurial Distributed SCM
list of commands (use "hg help -v" to show aliases and global options):
- add add the specified files on the next commit
- annotate show changeset information per file line
- archive create unversioned archive of a repository revision
- backout reverse effect of earlier changeset
- bundle create a changegroup file
- cat output the latest or given revisions of files
- clone make a copy of an existing repository
- commit commit the specified files or all outstanding changes
- copy mark files as copied for the next commit
- diff diff repository (or selected files)
- export dump the header and diffs for one or more changesets
- grep search for a pattern in specified files and revisions
- heads show current repository heads
- help show help for a command, extension, or list of commands
- identify print information about the working copy
- import import an ordered set of patches
- incoming show new changesets found in source
- init create a new repository in the given directory
- locate locate files matching specific patterns
- log show revision history of entire repository or files
- manifest output the latest or given revision of the project manifest
- merge Merge working directory with another revision
- outgoing show changesets not found in destination
- parents show the parents of the working dir or revision
- paths show definition of symbolic path names
- pull pull changes from the specified source
- push push changes to the specified destination
- recover roll back an interrupted transaction
- remove remove the specified files on the next commit
- rename rename files; equivalent of copy + remove
- revert revert files or dirs to their states as of some revision
- rollback roll back the last transaction in this repository
- root print the root (top) of the current working dir
- serve export the repository via HTTP
- status show changed files in the working directory
- tag add a tag for the current tip or a given revision
- tags list repository tags
- tip show the tip revision
- unbundle apply a changegroup file
- update update or merge working directory
- verify verify the integrity of the repository
- version output version and copyright information
+ add add the specified files on the next commit
+ addremove add all new files, delete all missing files (DEPRECATED)
+ annotate show changeset information per file line
+ archive create unversioned archive of a repository revision
+ backout reverse effect of earlier changeset
+ bundle create a changegroup file
+ cat output the latest or given revisions of files
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ copy mark files as copied for the next commit
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ grep search for a pattern in specified files and revisions
+ heads show current repository heads
+ help show help for a command, extension, or list of commands
+ identify print information about the working copy
+ import import an ordered set of patches
+ incoming show new changesets found in source
+ init create a new repository in the given directory
+ locate locate files matching specific patterns
+ log show revision history of entire repository or files
+ manifest output the latest or given revision of the project manifest
+ merge Merge working directory with another revision
+ outgoing show changesets not found in destination
+ parents show the parents of the working dir or revision
+ paths show definition of symbolic path names
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ recover roll back an interrupted transaction
+ remove remove the specified files on the next commit
+ rename rename files; equivalent of copy + remove
+ revert revert files or dirs to their states as of some revision
+ rollback roll back the last transaction in this repository
+ root print the root (top) of the current working dir
+ serve export the repository via HTTP
+ status show changed files in the working directory
+ tag add a tag for the current tip or a given revision
+ tags list repository tags
+ tip show the tip revision
+ unbundle apply a changegroup file
+ update update or merge working directory
+ verify verify the integrity of the repository
+ version output version and copyright information
%% not tested: --debugger
--- a/tests/test-grep Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-grep Tue Aug 22 07:55:10 2006 -0700
@@ -18,6 +18,13 @@
mv port1 port
hg commit -m 4 -u spam -d '4 0'
hg grep port port
-echo 'FIXME: history is wrong here'
hg grep --all -nu port port
hg grep import port
+
+hg cp port port2
+hg commit -m 4 -u spam -d '5 0'
+echo '% follow'
+hg grep -f 'import$' port2
+echo deport >> port2
+hg commit -m 5 -u eggs -d '6 0'
+hg grep -f --all -nu port port2
--- a/tests/test-grep.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-grep.out Tue Aug 22 07:55:10 2006 -0700
@@ -1,10 +1,25 @@
port:4:export
port:4:vaportight
port:4:import/export
-FIXME: history is wrong here
-port:1:1:-:eggs:import
-port:1:2:+:eggs:vaportight
-port:1:3:+:eggs:import/export
-port:0:2:+:spam:export
-port:0:1:+:spam:import
+port:4:4:-:spam:import/export
+port:3:4:+:eggs:import/export
+port:2:1:-:spam:import
+port:2:2:-:spam:export
+port:2:1:+:spam:export
+port:2:2:+:spam:vaportight
+port:2:3:+:spam:import/export
+port:1:2:+:eggs:export
+port:0:1:+:eggs:import
port:4:import/export
+% follow
+port:0:import
+port2:6:4:+:eggs:deport
+port:4:4:-:spam:import/export
+port:3:4:+:eggs:import/export
+port:2:1:-:spam:import
+port:2:2:-:spam:export
+port:2:1:+:spam:export
+port:2:2:+:spam:vaportight
+port:2:3:+:spam:import/export
+port:1:2:+:eggs:export
+port:0:1:+:eggs:import
--- a/tests/test-help.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-help.out Tue Aug 22 07:55:10 2006 -0700
@@ -38,90 +38,92 @@
list of commands (use "hg help -v" to show aliases and global options):
- add add the specified files on the next commit
- annotate show changeset information per file line
- archive create unversioned archive of a repository revision
- backout reverse effect of earlier changeset
- bundle create a changegroup file
- cat output the latest or given revisions of files
- clone make a copy of an existing repository
- commit commit the specified files or all outstanding changes
- copy mark files as copied for the next commit
- diff diff repository (or selected files)
- export dump the header and diffs for one or more changesets
- grep search for a pattern in specified files and revisions
- heads show current repository heads
- help show help for a command, extension, or list of commands
- identify print information about the working copy
- import import an ordered set of patches
- incoming show new changesets found in source
- init create a new repository in the given directory
- locate locate files matching specific patterns
- log show revision history of entire repository or files
- manifest output the latest or given revision of the project manifest
- merge Merge working directory with another revision
- outgoing show changesets not found in destination
- parents show the parents of the working dir or revision
- paths show definition of symbolic path names
- pull pull changes from the specified source
- push push changes to the specified destination
- recover roll back an interrupted transaction
- remove remove the specified files on the next commit
- rename rename files; equivalent of copy + remove
- revert revert files or dirs to their states as of some revision
- rollback roll back the last transaction in this repository
- root print the root (top) of the current working dir
- serve export the repository via HTTP
- status show changed files in the working directory
- tag add a tag for the current tip or a given revision
- tags list repository tags
- tip show the tip revision
- unbundle apply a changegroup file
- update update or merge working directory
- verify verify the integrity of the repository
- version output version and copyright information
- add add the specified files on the next commit
- annotate show changeset information per file line
- archive create unversioned archive of a repository revision
- backout reverse effect of earlier changeset
- bundle create a changegroup file
- cat output the latest or given revisions of files
- clone make a copy of an existing repository
- commit commit the specified files or all outstanding changes
- copy mark files as copied for the next commit
- diff diff repository (or selected files)
- export dump the header and diffs for one or more changesets
- grep search for a pattern in specified files and revisions
- heads show current repository heads
- help show help for a command, extension, or list of commands
- identify print information about the working copy
- import import an ordered set of patches
- incoming show new changesets found in source
- init create a new repository in the given directory
- locate locate files matching specific patterns
- log show revision history of entire repository or files
- manifest output the latest or given revision of the project manifest
- merge Merge working directory with another revision
- outgoing show changesets not found in destination
- parents show the parents of the working dir or revision
- paths show definition of symbolic path names
- pull pull changes from the specified source
- push push changes to the specified destination
- recover roll back an interrupted transaction
- remove remove the specified files on the next commit
- rename rename files; equivalent of copy + remove
- revert revert files or dirs to their states as of some revision
- rollback roll back the last transaction in this repository
- root print the root (top) of the current working dir
- serve export the repository via HTTP
- status show changed files in the working directory
- tag add a tag for the current tip or a given revision
- tags list repository tags
- tip show the tip revision
- unbundle apply a changegroup file
- update update or merge working directory
- verify verify the integrity of the repository
- version output version and copyright information
+ add add the specified files on the next commit
+ addremove add all new files, delete all missing files (DEPRECATED)
+ annotate show changeset information per file line
+ archive create unversioned archive of a repository revision
+ backout reverse effect of earlier changeset
+ bundle create a changegroup file
+ cat output the latest or given revisions of files
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ copy mark files as copied for the next commit
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ grep search for a pattern in specified files and revisions
+ heads show current repository heads
+ help show help for a command, extension, or list of commands
+ identify print information about the working copy
+ import import an ordered set of patches
+ incoming show new changesets found in source
+ init create a new repository in the given directory
+ locate locate files matching specific patterns
+ log show revision history of entire repository or files
+ manifest output the latest or given revision of the project manifest
+ merge Merge working directory with another revision
+ outgoing show changesets not found in destination
+ parents show the parents of the working dir or revision
+ paths show definition of symbolic path names
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ recover roll back an interrupted transaction
+ remove remove the specified files on the next commit
+ rename rename files; equivalent of copy + remove
+ revert revert files or dirs to their states as of some revision
+ rollback roll back the last transaction in this repository
+ root print the root (top) of the current working dir
+ serve export the repository via HTTP
+ status show changed files in the working directory
+ tag add a tag for the current tip or a given revision
+ tags list repository tags
+ tip show the tip revision
+ unbundle apply a changegroup file
+ update update or merge working directory
+ verify verify the integrity of the repository
+ version output version and copyright information
+ add add the specified files on the next commit
+ addremove add all new files, delete all missing files (DEPRECATED)
+ annotate show changeset information per file line
+ archive create unversioned archive of a repository revision
+ backout reverse effect of earlier changeset
+ bundle create a changegroup file
+ cat output the latest or given revisions of files
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ copy mark files as copied for the next commit
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ grep search for a pattern in specified files and revisions
+ heads show current repository heads
+ help show help for a command, extension, or list of commands
+ identify print information about the working copy
+ import import an ordered set of patches
+ incoming show new changesets found in source
+ init create a new repository in the given directory
+ locate locate files matching specific patterns
+ log show revision history of entire repository or files
+ manifest output the latest or given revision of the project manifest
+ merge Merge working directory with another revision
+ outgoing show changesets not found in destination
+ parents show the parents of the working dir or revision
+ paths show definition of symbolic path names
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ recover roll back an interrupted transaction
+ remove remove the specified files on the next commit
+ rename rename files; equivalent of copy + remove
+ revert revert files or dirs to their states as of some revision
+ rollback roll back the last transaction in this repository
+ root print the root (top) of the current working dir
+ serve export the repository via HTTP
+ status show changed files in the working directory
+ tag add a tag for the current tip or a given revision
+ tags list repository tags
+ tip show the tip revision
+ unbundle apply a changegroup file
+ update update or merge working directory
+ verify verify the integrity of the repository
+ version output version and copyright information
hg add [OPTION]... [FILE]...
add the specified files on the next commit
@@ -176,6 +178,7 @@
-r --rev revision
-a --text treat all files as text
-p --show-function show which function each change is in
+ -g --git use git extended diff format
-w --ignore-all-space ignore white space when comparing lines
-b --ignore-space-change ignore changes in the amount of white space
-B --ignore-blank-lines ignore changes whose lines are all blank
--- a/tests/test-hook.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-hook.out Tue Aug 22 07:55:10 2006 -0700
@@ -36,43 +36,43 @@
(run 'hg update' to get a working copy)
pretag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
precommit hook: p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
-pretxncommit hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
-4:4f92e785b90a
-commit hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
+pretxncommit hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
+4:8ea2ef7ad3e8
+commit hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p1=4c52fb2e402287dd5dc052090682536c8406c321 p2=
commit hook b
tag hook: t=a n=4c52fb2e402287dd5dc052090682536c8406c321 l=0
-pretag hook: t=la n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
-tag hook: t=la n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
-pretag hook: t=fa n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=0
+pretag hook: t=la n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
+tag hook: t=la n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
+pretag hook: t=fa n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=0
pretag.forbid hook
abort: pretag.forbid hook exited with status 1
-pretag hook: t=fla n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 l=1
+pretag hook: t=fla n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 l=1
pretag.forbid hook
abort: pretag.forbid hook exited with status 1
-4:4f92e785b90a
-precommit hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
-pretxncommit hook: n=7792358308a2026661cea44f9d47c072813004cb p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
-5:7792358308a2
-pretxncommit.forbid hook: tip=5:7792358308a2
+4:8ea2ef7ad3e8
+precommit hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
+pretxncommit hook: n=fad284daf8c032148abaffcd745dafeceefceb61 p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
+5:fad284daf8c0
+pretxncommit.forbid hook: tip=5:fad284daf8c0
abort: pretxncommit.forbid hook exited with status 1
transaction abort!
rollback completed
-4:4f92e785b90a
-precommit hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
+4:8ea2ef7ad3e8
+precommit hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
precommit.forbid hook
abort: precommit.forbid hook exited with status 1
-4:4f92e785b90a
+4:8ea2ef7ad3e8
preupdate hook: p1=b702efe9688826e3a91283852b328b84dbf37bc2 p2=
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
-preupdate hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2=
-update hook: p1=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 p2= err=0
+preupdate hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2=
+update hook: p1=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 p2= err=0
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
3:4c52fb2e4022
prechangegroup.forbid hook
pulling from ../a
searching for changes
abort: prechangegroup.forbid hook exited with status 1
-pretxnchangegroup.forbid hook: tip=4:4f92e785b90a
+pretxnchangegroup.forbid hook: tip=4:8ea2ef7ad3e8
pulling from ../a
searching for changes
adding changesets
@@ -84,7 +84,7 @@
rollback completed
3:4c52fb2e4022
preoutgoing hook: s=pull
-outgoing hook: n=4f92e785b90ae8995dfe156e39dd4fbc3b346a24 s=pull
+outgoing hook: n=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 s=pull
pulling from ../a
searching for changes
adding changesets
--- a/tests/test-http Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-http Tue Aug 22 07:55:10 2006 -0700
@@ -11,7 +11,7 @@
echo % clone via stream
http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \
- sed -e 's/[0-9][0-9.]*/XXX/g'
+ sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/.\(B\/sec\)/X\1/'
hg verify -R copy
echo % try to clone via stream, should use pull instead
--- a/tests/test-http.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-http.out Tue Aug 22 07:55:10 2006 -0700
@@ -2,7 +2,7 @@
% clone via stream
streaming all changes
XXX files to transfer, XXX bytes of data
-transferred XXX bytes in XXX seconds (XXX KB/sec)
+transferred XXX bytes in XXX seconds (XXX XB/sec)
XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
checking changesets
checking manifests
--- a/tests/test-import Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-import Tue Aug 22 07:55:10 2006 -0700
@@ -72,7 +72,7 @@
echo % plain diff in email, no subject, no message body, should fail
hg clone -r0 a b
-grep -v '^\(Subject\|email\)' msg.patch | hg --cwd b import -
+egrep -v '^(Subject|email)' msg.patch | hg --cwd b import -
rm -rf b
echo % hg export in email, should use patch header
@@ -89,9 +89,10 @@
echo % hg import in a subdirectory
hg clone -r0 a b
hg --cwd a export tip | sed -e 's/d1\/d2\///' > tip.patch
-pushd b/d1/d2 2>&1 > /dev/null
+dir=`pwd`
+cd b/d1/d2 2>&1 > /dev/null
hg import ../../../tip.patch
-popd 2>&1 > /dev/null
+cd $dir
echo "% message should be 'subdir change'"
hg --cwd b tip | grep 'subdir change'
echo "% committer should be 'someoneelse'"
--- a/tests/test-import.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-import.out Tue Aug 22 07:55:10 2006 -0700
@@ -8,7 +8,6 @@
added 1 changesets with 2 changes to 2 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying ../tip.patch
-patching file a
% message should be same
summary: second change
% committer should be same
@@ -21,7 +20,6 @@
added 1 changesets with 2 changes to 2 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying ../tip.patch
-patching file a
transaction abort!
rollback completed
% import of plain diff should be ok with message
@@ -32,7 +30,6 @@
added 1 changesets with 2 changes to 2 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying ../tip.patch
-patching file a
% import from stdin
requesting all changes
adding changesets
@@ -41,7 +38,6 @@
added 1 changesets with 2 changes to 2 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying patch from stdin
-patching file a
% override commit message
requesting all changes
adding changesets
@@ -50,7 +46,6 @@
added 1 changesets with 2 changes to 2 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying patch from stdin
-patching file a
summary: override
% plain diff in email, subject, message body
requesting all changes
@@ -60,7 +55,6 @@
added 1 changesets with 2 changes to 2 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying ../msg.patch
-patching file a
user: email patcher
summary: email patch
% plain diff in email, no subject, message body
@@ -71,7 +65,6 @@
added 1 changesets with 2 changes to 2 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying patch from stdin
-patching file a
% plain diff in email, subject, no message body
requesting all changes
adding changesets
@@ -80,7 +73,6 @@
added 1 changesets with 2 changes to 2 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying patch from stdin
-patching file a
% plain diff in email, no subject, no message body, should fail
requesting all changes
adding changesets
@@ -89,7 +81,6 @@
added 1 changesets with 2 changes to 2 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying patch from stdin
-patching file a
transaction abort!
rollback completed
% hg export in email, should use patch header
@@ -100,7 +91,6 @@
added 1 changesets with 2 changes to 2 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying patch from stdin
-patching file a
summary: second change
% hg import in a subdirectory
requesting all changes
@@ -110,7 +100,6 @@
added 1 changesets with 2 changes to 2 files
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying ../../../tip.patch
-patching file a
% message should be 'subdir change'
summary: subdir change
% committer should be 'someoneelse'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-issue322 Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,49 @@
+#!/bin/sh
+# http://www.selenic.com/mercurial/bts/issue322
+
+echo % file replaced with directory
+
+hg init a
+cd a
+echo a > a
+hg commit -Ama
+rm a
+mkdir a
+echo a > a/a
+
+echo % should fail - would corrupt dirstate
+hg add a/a
+
+cd ..
+
+echo % directory replaced with file
+
+hg init c
+cd c
+mkdir a
+echo a > a/a
+hg commit -Ama
+
+rm -rf a
+echo a > a
+
+echo % should fail - would corrupt dirstate
+hg add a
+
+cd ..
+
+echo % directory replaced with file
+
+hg init d
+cd d
+mkdir b
+mkdir b/c
+echo a > b/c/d
+hg commit -Ama
+rm -rf b
+echo a > b
+
+echo % should fail - would corrupt dirstate
+hg add b
+
+exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-issue322.out Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,12 @@
+% file replaced with directory
+adding a
+% should fail - would corrupt dirstate
+abort: file named 'a' already in dirstate
+% directory replaced with file
+adding a/a
+% should fail - would corrupt dirstate
+abort: directory named 'a' already in dirstate
+% directory replaced with file
+adding b/c/d
+% should fail - would corrupt dirstate
+abort: directory named 'b' already in dirstate
--- a/tests/test-log Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-log Tue Aug 22 07:55:10 2006 -0700
@@ -63,3 +63,6 @@
echo % log --follow-first
hg log --follow-first
+
+echo % log -P 2
+hg log -P 2
--- a/tests/test-log.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-log.out Tue Aug 22 07:55:10 2006 -0700
@@ -34,7 +34,7 @@
summary: a
% one rename
-changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
+changeset: 0:8580ff50825a
user: test
date: Thu Jan 01 00:00:01 1970 +0000
files: a
@@ -43,7 +43,7 @@
% many renames
-changeset: 4:8c1c8408f7371319750ea2d4fa7969828effbcf4
+changeset: 4:8c1c8408f737
tag: tip
user: test
date: Thu Jan 01 00:00:05 1970 +0000
@@ -52,7 +52,7 @@
e
-changeset: 2:21fba396af4c801f9717de6c415b6cc9620437e8
+changeset: 2:21fba396af4c
user: test
date: Thu Jan 01 00:00:03 1970 +0000
files: b dir/b
@@ -60,7 +60,7 @@
c
-changeset: 1:c0296dabce9bf0cd3fdd608de26693c91cd6bbf4
+changeset: 1:c0296dabce9b
user: test
date: Thu Jan 01 00:00:02 1970 +0000
files: b
@@ -68,7 +68,7 @@
b
-changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
+changeset: 0:8580ff50825a
user: test
date: Thu Jan 01 00:00:01 1970 +0000
files: a
@@ -149,3 +149,29 @@
date: Thu Jan 01 00:00:01 1970 +0000
summary: base
+% log -P 2
+changeset: 6:2404bbcab562
+tag: tip
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: b1.1
+
+changeset: 5:302e9dd6890d
+parent: 3:e62f78d544b4
+parent: 4:ddb82e70d1a1
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: m12
+
+changeset: 4:ddb82e70d1a1
+parent: 0:67e992f2c4f3
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: b2
+
+changeset: 3:e62f78d544b4
+parent: 1:3d5bf5654eda
+user: test
+date: Thu Jan 01 00:00:01 1970 +0000
+summary: b1
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-merge-default Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+hg init
+echo a > a
+hg commit -A -ma
+
+echo a >> a
+hg commit -mb
+
+echo a >> a
+hg commit -mc
+
+hg up 1
+echo a >> a
+hg commit -md
+
+hg up 1
+echo a >> a
+hg commit -me
+
+hg up 1
+echo % should fail because not at a head
+hg merge
+
+hg up
+echo % should fail because \> 2 heads
+hg merge
+
+echo % should succeed
+hg merge 2
+hg commit -mm1
+
+echo % should succeed - 2 heads
+hg merge
+hg commit -mm2
+
+echo % should fail because 1 head
+hg merge
+
+true
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-merge-default.out Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,17 @@
+adding a
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% should fail because not at a head
+abort: repo has 3 heads - please merge with an explicit rev
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% should fail because > 2 heads
+abort: repo has 3 heads - please merge with an explicit rev
+% should succeed
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% should succeed - 2 heads
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+(branch merge, don't forget to commit)
+% should fail because 1 head
+abort: there is nothing to merge - use "hg update" instead
--- a/tests/test-merge-revert Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-merge-revert Tue Aug 22 07:55:10 2006 -0700
@@ -15,7 +15,7 @@
hg id
echo "changed file1" >> file1
hg id
-hg revert
+hg revert --all
hg diff
hg status
hg id
@@ -29,11 +29,11 @@
hg diff
hg status
hg id
-hg revert
+hg revert --all
hg diff
hg status
hg id
-hg revert -r tip
+hg revert -r tip --all
hg diff
hg status
hg id
--- a/tests/test-merge-revert2 Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-merge-revert2 Tue Aug 22 07:55:10 2006 -0700
@@ -16,7 +16,7 @@
hg id
echo "changed file1" >> file1
hg id
-hg revert --no-backup
+hg revert --no-backup --all
hg diff
hg status
hg id
@@ -31,11 +31,11 @@
-e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" -e "s/\(>>>>>>>\) .*/\1/"
hg status
hg id
-hg revert --no-backup
+hg revert --no-backup --all
hg diff
hg status
hg id
-hg revert -r tip --no-backup
+hg revert -r tip --no-backup --all
hg diff
hg status
hg id
--- a/tests/test-mq Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-mq Tue Aug 22 07:55:10 2006 -0700
@@ -1,8 +1,7 @@
#!/bin/sh
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
echo % help
hg help mq
@@ -10,6 +9,10 @@
hg init a
cd a
echo a > a
+hg ci -Ama
+
+hg clone . ../k
+
mkdir b
echo z > b/z
hg ci -Ama
@@ -48,7 +51,7 @@
echo a >> a
hg qrefresh
-sed -e "s/\(^diff -r \)\([a-f0-9]* \)/\1 x/" \
+sed -e "s/^\(diff -r \)\([a-f0-9]* \)/\1 x/" \
-e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
-e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/test.patch
@@ -103,12 +106,49 @@
hg qprev
hg qapplied
+echo % commit should fail
+hg commit
+
+echo % push should fail
+hg push ../../k
+
echo % qunapplied
hg qunapplied
+echo % push should succeed
+hg qpop -a
+hg push ../../k
+
echo % strip
cd ../../b
echo x>x
hg ci -Ama
hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
hg unbundle .hg/strip-backup/*
+
+cat >>$HGRCPATH <<EOF
+[diff]
+git = True
+EOF
+cd ..
+hg init git
+cd git
+hg qinit
+
+hg qnew -m'new file' new
+echo foo > new
+chmod +x new
+hg add new
+hg qrefresh
+sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/new
+
+hg qnew -m'copy file' copy
+hg cp new copy
+hg qrefresh
+sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/copy
+
+hg qpop
+hg qpush
+hg qdiff
--- a/tests/test-mq-guards Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-mq-guards Tue Aug 22 07:55:10 2006 -0700
@@ -1,8 +1,7 @@
#!/bin/sh
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
hg init
hg qinit
@@ -63,22 +62,39 @@
hg qpush -a
hg qpop -a
-hg qguard a.patch +1 +2
+hg qguard a.patch +1
+hg qguard b.patch +2
hg qselect 1
+echo % should push a.patch, not b.patch
+hg qpush
+hg qpush
+hg qpop -a
+
+hg qselect 2
echo % should push b.patch
hg qpush
hg qpop -a
-hg qselect 2
+hg qselect 1 2
+echo % should push a.patch, b.patch
hg qpush
-hg qpop -a
-
-hg qselect 1 2
-echo % should push a.patch
hg qpush
hg qpop -a
hg qguard a.patch +1 +2 -3
hg qselect 1 2 3
+echo % list patches and guards
+hg qguard -l
+echo % list series
+hg qseries -v
+echo % list guards
+hg qselect
echo % should push b.patch
hg qpush
+
+hg qpush -a
+hg qselect -n --reapply
+echo % guards in series file: +1 +2 -3
+hg qselect -s
+echo % should show c.patch
+hg qapplied
--- a/tests/test-mq-guards.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-mq-guards.out Tue Aug 22 07:55:10 2006 -0700
@@ -13,7 +13,7 @@
applying b.patch
Now at: b.patch
Patch queue now empty
-3 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 2 to 3
% should push a.patch
applying a.patch
Now at: a.patch
@@ -28,27 +28,57 @@
Now at: c.patch
Patch queue now empty
guards deactivated
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 3 to 2
% should push all
applying b.patch
applying c.patch
Now at: c.patch
Patch queue now empty
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 1 to 2
+% should push a.patch, not b.patch
+applying a.patch
+Now at: a.patch
+applying c.patch
+Now at: c.patch
+Patch queue now empty
% should push b.patch
applying b.patch
Now at: b.patch
Patch queue now empty
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 2 to 3
+% should push a.patch, b.patch
+applying a.patch
+Now at: a.patch
applying b.patch
Now at: b.patch
Patch queue now empty
-3 of 3 unapplied patches active
-% should push a.patch
-applying a.patch
-Now at: a.patch
-Patch queue now empty
-2 of 3 unapplied patches active
+number of unguarded, unapplied patches has changed from 3 to 2
+% list patches and guards
+a.patch: +1 +2 -3
+b.patch: +2
+c.patch: unguarded
+% list series
+0 G a.patch
+1 U b.patch
+2 U c.patch
+% list guards
+1
+2
+3
% should push b.patch
applying b.patch
Now at: b.patch
+applying c.patch
+Now at: c.patch
+guards deactivated
+popping guarded patches
+Patch queue now empty
+reapplying unguarded patches
+applying c.patch
+Now at: c.patch
+% guards in series file: +1 +2 -3
++1
++2
+-3
+% should show c.patch
+c.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qdiff Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
+
+echo % init
+hg init a
+cd a
+
+echo % commit
+echo 'base' > base
+hg ci -Ambase -d '1 0'
+
+echo % qnew mqbase
+hg qnew -mmqbase mqbase
+
+echo % qrefresh
+echo 'patched' > base
+hg qrefresh
+
+echo % qdiff
+hg qdiff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
+
+echo % qdiff dirname
+hg qdiff . | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \
+ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qdiff.out Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,19 @@
+% init
+% commit
+adding base
+% qnew mqbase
+% qrefresh
+% qdiff
+diff -r 67e992f2c4f3 base
+--- a/base
++++ b/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
+% qdiff dirname
+diff -r 67e992f2c4f3 base
+--- a/base
++++ b/base
+@@ -1,1 +1,1 @@ base
+-base
++patched
--- a/tests/test-mq-qnew-twice Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-mq-qnew-twice Tue Aug 22 07:55:10 2006 -0700
@@ -1,8 +1,7 @@
#!/bin/sh
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
hg init a
cd a
--- a/tests/test-mq-qrefresh-replace-log-message Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-mq-qrefresh-replace-log-message Tue Aug 22 07:55:10 2006 -0700
@@ -1,9 +1,8 @@
#!/bin/sh
# Environement setup for MQ
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
#Repo init
hg init
@@ -33,7 +32,7 @@
echo bbbb > file
hg qrefresh -l logfile
echo =======================
-echo "Should display 'Third commit message\n This is the 3rd log message'"
+printf "Should display 'Third commit message\\\n This is the 3rd log message'\n"
hg log -l1 -v | sed -n '/description/,$p'
echo
@@ -46,6 +45,6 @@
echo " This is the 5th log message" >> logfile) |\
hg qrefresh -l-
echo =======================
-echo "Should display 'Fifth commit message\n This is the 5th log message'"
+printf "Should display 'Fifth commit message\\\n This is the 5th log message'\n"
hg log -l1 -v | sed -n '/description/,$p'
echo
--- a/tests/test-mq-qsave Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-mq-qsave Tue Aug 22 07:55:10 2006 -0700
@@ -1,8 +1,7 @@
#!/bin/sh
-HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
-echo "[extensions]" >> $HGTMP/.hgrc
-echo "mq=" >> $HGTMP/.hgrc
+echo "[extensions]" >> $HGRCPATH
+echo "mq=" >> $HGRCPATH
hg init a
cd a
--- a/tests/test-mq.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-mq.out Tue Aug 22 07:55:10 2006 -0700
@@ -27,7 +27,7 @@
qapplied print the patches already applied
qclone clone main and patch repository at same time
qcommit commit changes in the queue repository
- qdelete remove a patch from the series file
+ qdelete remove patches from queue
qdiff diff of the current patch
qfold fold the named patches into the current patch
qguard set or print guards for a patch
@@ -49,6 +49,7 @@
qunapplied print the patches not yet applied
strip strip a revision and all later revs on the same branch
adding a
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
adding b/z
% qinit
% -R qinit
@@ -102,8 +103,21 @@
test2.patch
Only one patch applied
test.patch
+% commit should fail
+abort: cannot commit over an applied mq patch
+% push should fail
+pushing to ../../k
+abort: source has mq patches applied
% qunapplied
test2.patch
+% push should succeed
+Patch queue now empty
+pushing to ../../k
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
% strip
adding x
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
@@ -113,3 +127,22 @@
adding file changes
added 1 changesets with 1 changes to 1 files
(run 'hg update' to get a working copy)
+new file
+
+diff --git a/new b/new
+new file mode 100755
+--- /dev/null
++++ b/new
+@@ -0,0 +1,1 @@
++foo
+copy file
+
+diff --git a/new b/copy
+copy from new
+copy to copy
+Now at: new
+applying copy
+Now at: copy
+diff --git a/new b/copy
+copy from new
+copy to copy
--- a/tests/test-nested-repo Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-nested-repo Tue Aug 22 07:55:10 2006 -0700
@@ -14,6 +14,6 @@
echo '# should print A b/x'
hg st
echo '# should forget b/x'
-hg revert
+hg revert --all
echo '# should print nothing'
hg st b
--- a/tests/test-parse-date.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-parse-date.out Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,6 @@
reverting a
changeset 3:107ce1ee2b43 backs out changeset 1:25a1420a55f8
-merging with changeset 2:99a1acecff55
+merging with changeset 2:e6c3abc120e7
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
abort: invalid date: 'should fail'
--- a/tests/test-pull.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-pull.out Tue Aug 22 07:55:10 2006 -0700
@@ -1,4 +1,3 @@
-(the addremove command is deprecated; use add and remove --after instead)
adding foo
checking changesets
checking manifests
--- a/tests/test-remove Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-remove Tue Aug 22 07:55:10 2006 -0700
@@ -9,7 +9,7 @@
hg remove
rm foo
hg remove foo
-hg revert
+hg revert --all
rm foo
hg remove --after
hg commit -m 2 -d "1000000 0"
--- a/tests/test-revert Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-revert Tue Aug 22 07:55:10 2006 -0700
@@ -31,7 +31,7 @@
ls
echo %% should verbosely save backup to e.orig
echo z > e
-hg revert -v
+hg revert --all -v
echo %% should say no changes needed
hg revert a
echo %% should say file not managed
@@ -46,9 +46,9 @@
hg add z
hg st
echo %% should add a, forget z
-hg revert -r0
+hg revert --all -r0
echo %% should forget a
-hg revert -rtip
+hg revert --all -rtip
rm -f a *.orig
echo %% should silently add a
hg revert -r0 a
@@ -56,7 +56,7 @@
hg update -C
chmod +x c
-hg revert
+hg revert --all
echo %% should print non-executable
test -x c || echo non-executable
@@ -64,7 +64,7 @@
hg commit -d '1000001 0' -m exe
chmod -x c
-hg revert
+hg revert --all
echo %% should print executable
test -x c && echo executable
@@ -78,6 +78,11 @@
hg update 0
mkdir b
echo b > b/b
+
+echo % should fail - no arguments
hg revert -rtip
+echo % should succeed
+hg revert --all -rtip
+
true
--- a/tests/test-revert-unknown Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-revert-unknown Tue Aug 22 07:55:10 2006 -0700
@@ -13,7 +13,7 @@
echo %% Should show unknown
hg status
-hg revert -r 0
+hg revert -r 0 --all
echo %% Should show unknown and b removed
hg status
echo %% Should show a and unknown
--- a/tests/test-revert.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-revert.out Tue Aug 22 07:55:10 2006 -0700
@@ -54,4 +54,7 @@
%% issue 241
adding a
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% should fail - no arguments
+abort: no files or directories specified
+% should succeed
reverting a
--- a/tests/test-simple-update.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-simple-update.out Tue Aug 22 07:55:10 2006 -0700
@@ -1,4 +1,3 @@
-(the addremove command is deprecated; use add and remove --after instead)
adding foo
checking changesets
checking manifests
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-strict Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+hg init
+
+echo a > a
+hg ci -d '0 0' -Ama
+
+hg an a
+
+echo "[ui]" >> $HGRCPATH
+echo "strict=True" >> $HGRCPATH
+
+hg an a
+hg annotate a
+
+echo % should succeed - up is an alias, not an abbreviation
+
+hg up
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-strict.out Tue Aug 22 07:55:10 2006 -0700
@@ -0,0 +1,26 @@
+adding a
+0: a
+hg: unknown command 'an'
+Mercurial Distributed SCM
+
+basic commands (use "hg help" for the full list or option "-v" for details):
+
+ add add the specified files on the next commit
+ annotate show changeset information per file line
+ clone make a copy of an existing repository
+ commit commit the specified files or all outstanding changes
+ diff diff repository (or selected files)
+ export dump the header and diffs for one or more changesets
+ init create a new repository in the given directory
+ log show revision history of entire repository or files
+ parents show the parents of the working dir or revision
+ pull pull changes from the specified source
+ push push changes to the specified destination
+ remove remove the specified files on the next commit
+ revert revert files or dirs to their states as of some revision
+ serve export the repository via HTTP
+ status show changed files in the working directory
+ update update or merge working directory
+0: a
+% should succeed - up is an alias, not an abbreviation
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-symlinks.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-symlinks.out Tue Aug 22 07:55:10 2006 -0700
@@ -1,6 +1,4 @@
-(the addremove command is deprecated; use add and remove --after instead)
adding foo
-(the addremove command is deprecated; use add and remove --after instead)
adding bomb
adding a.c
adding dir/a.o
--- a/tests/test-tag.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-tag.out Tue Aug 22 07:55:10 2006 -0700
@@ -4,11 +4,11 @@
date: Mon Jan 12 13:46:40 1970 +0000
summary: test
-changeset: 1:c5c60883086f
+changeset: 1:3ecf002a1c57
tag: tip
user: test
date: Mon Jan 12 13:46:40 1970 +0000
-summary: Added tag bleah for changeset 0acdaf8983679e0aac16e811534eb49d7ee1f2b4
+summary: Added tag bleah for changeset 0acdaf898367
changeset: 0:0acdaf898367
tag: bleah
@@ -24,9 +24,9 @@
use of 'hg tag NAME [REV]' is deprecated, please use 'hg tag [-r REV] NAME' instead
0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah
0acdaf8983679e0aac16e811534eb49d7ee1f2b4 bleah0
-c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1
+3ecf002a1c572a2f3bb4e665417e60fca65bbd42 bleah1
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar
-c5c60883086f5526bd3e36814b94a73a4e75e172 bleah1
+3ecf002a1c572a2f3bb4e665417e60fca65bbd42 bleah1
abort: '\n' cannot be used in a tag name
abort: ':' cannot be used in a tag name
--- a/tests/test-tags Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-tags Tue Aug 22 07:55:10 2006 -0700
@@ -9,7 +9,7 @@
hg commit -m "test" -d "1000000 0"
hg co
hg identify
-T=`hg tip -v | head -n 1 | cut -d : -f 3`
+T=`hg tip --debug | head -n 1 | cut -d : -f 3`
echo "$T first" > .hgtags
cat .hgtags
hg add .hgtags
--- a/tests/test-tags.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-tags.out Tue Aug 22 07:55:10 2006 -0700
@@ -2,35 +2,35 @@
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
0acdaf898367 tip
0acdaf8983679e0aac16e811534eb49d7ee1f2b4 first
-tip 1:8a3ca90d111dc784e6575d373105be12570e8776
-first 0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
+tip 1:8a3ca90d111d
+first 0:0acdaf898367
8a3ca90d111d tip
M a
8a3ca90d111d+ tip
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
0acdaf898367+ first
-0acdaf8983679e0aac16e811534eb49d7ee1f2b4+ first
+0acdaf898367+ first
M a
8216907a933d tip
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
8216907a933d+8a3ca90d111d+ tip
M .hgtags
-tip 6:c6af9d771a81bb9c7f267ec03491224a9f8ba1cd
-first 0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
-.hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
-.hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
+tip 6:e2174d339386
+first 0:0acdaf898367
+.hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
+.hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
localtags, line 1: tag 'invalid' refers to unknown node
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-.hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
-.hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
+.hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
+.hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
.hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
localtags, line 1: tag 'invalid' refers to unknown node
-tip 8:4ca6f1b1a68c77be687a03aaeb1614671ba59b20
-first 0:0acdaf8983679e0aac16e811534eb49d7ee1f2b4
+tip 8:4ca6f1b1a68c
+first 0:0acdaf898367
changeset: 8:4ca6f1b1a68c
-.hgtags (rev 7:39bba1bbbc4c), line 2: cannot parse entry
-.hgtags (rev 7:39bba1bbbc4c), line 4: node 'foo' is not well formed
+.hgtags (rev 7:c071f74ab5eb), line 2: cannot parse entry
+.hgtags (rev 7:c071f74ab5eb), line 4: node 'foo' is not well formed
.hgtags (rev 8:4ca6f1b1a68c), line 2: node 'x' is not well formed
localtags, line 1: tag 'invalid' refers to unknown node
tag: tip
--- a/tests/test-up-local-change.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-up-local-change.out Tue Aug 22 07:55:10 2006 -0700
@@ -1,4 +1,3 @@
-(the addremove command is deprecated; use add and remove --after instead)
adding a
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -8,7 +7,6 @@
@@ -1,1 +1,1 @@ a
-a
+abc
-(the addremove command is deprecated; use add and remove --after instead)
adding b
M a
changeset: 0:33aaa84a386b
@@ -43,7 +41,7 @@
date: Mon Jan 12 13:46:40 1970 +0000
summary: 1
-abort: there is nothing to merge, just use 'hg update' or look at 'hg heads'
+abort: there is nothing to merge - use "hg update" instead
failed
changeset: 0:33aaa84a386b
user: test
@@ -66,7 +64,7 @@
date: Mon Jan 12 13:46:40 1970 +0000
summary: 2
-changeset: 1:802f095af299cde27a85b2f056aef3829870956c
+changeset: 1:802f095af299
tag: tip
user: test
date: Mon Jan 12 13:46:40 1970 +0000
@@ -75,7 +73,7 @@
2
-changeset: 0:33aaa84a386bd609094aeb21a97c09436c482ef1
+changeset: 0:33aaa84a386b
user: test
date: Mon Jan 12 13:46:40 1970 +0000
files: a
@@ -90,7 +88,6 @@
-a2
+abc
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
-(the addremove command is deprecated; use add and remove --after instead)
adding b
M a
changeset: 1:802f095af299
--- a/tests/test-walk.out Thu Aug 10 16:59:58 2006 +0200
+++ b/tests/test-walk.out Tue Aug 22 07:55:10 2006 -0700
@@ -1,4 +1,3 @@
-(the addremove command is deprecated; use add and remove --after instead)
adding beans/black
adding beans/borlotti
adding beans/kidney