--- a/contrib/mercurial.el Mon Aug 14 14:14:08 2006 -0500
+++ b/contrib/mercurial.el Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/doc/hg.1.txt Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/doc/hgmerge.1.txt Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/doc/hgrc.5.txt Mon Aug 14 14:42:15 2006 -0500
@@ -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;;
--- a/doc/ja/hg.1.ja.txt Mon Aug 14 14:14:08 2006 -0500
+++ b/doc/ja/hg.1.ja.txt Mon Aug 14 14:42:15 2006 -0500
@@ -862,6 +862,6 @@
著作権情報
-----
-Copyright (C) 2005 Matt Mackall.
+Copyright (C) 2005, 2006 Matt Mackall.
このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
認められます。
--- a/doc/ja/hgmerge.1.ja.txt Mon Aug 14 14:14:08 2006 -0500
+++ b/doc/ja/hgmerge.1.ja.txt Mon Aug 14 14:42:15 2006 -0500
@@ -32,6 +32,6 @@
著作権情報
----
-Copyright (C) 2005 Matt Mackall.
+Copyright (C) 2005, 2006 Matt Mackall.
このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
認められます。
--- a/hgext/extdiff.py Mon Aug 14 14:14:08 2006 -0500
+++ b/hgext/extdiff.py Mon Aug 14 14:42:15 2006 -0500
@@ -80,8 +80,8 @@
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)
+ modified, added, removed, deleted, unknown = repo.status(
+ node1, node2, files, match=matchfn)[:5]
if not (modified or added or removed):
return 0
--- a/hgext/fetch.py Mon Aug 14 14:14:08 2006 -0500
+++ b/hgext/fetch.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/hgext/gpg.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/hgext/hbisect.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/hgext/hgk.py Mon Aug 14 14:42:15 2006 -0500
@@ -1,6 +1,6 @@
# 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.
@@ -14,7 +14,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 +67,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 Mon Aug 14 14:14:08 2006 -0500
+++ b/hgext/mq.py Mon Aug 14 14:42:15 2006 -0500
@@ -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,9 @@
'''
from mercurial.demandload import *
+from mercurial.i18n import gettext as _
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,commands,hg,patch,revlog,ui,util")
commands.norepo += " qclone qversion"
@@ -66,6 +65,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 +75,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 = self.ui.diffopts()
+ return self._diffopts
+
def join(self, *p):
return os.path.join(self.path, *p)
@@ -176,11 +181,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):
@@ -292,6 +297,11 @@
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=None):
+ patch.diff(repo, node1, node2, files,
+ 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 +335,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)
@@ -470,8 +480,7 @@
cfiles = files
if cwd:
cfiles = [util.pathto(cwd, f) for f in files]
- commands.addremove_lock(self.ui, repo, cfiles,
- opts={}, wlock=wlock)
+ cmdutil.addremove(repo, cfiles, wlock=wlock)
n = repo.commit(files, message, user, date, force=1, lock=lock,
wlock=wlock)
@@ -523,19 +532,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 +571,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 +659,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 +733,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
@@ -887,15 +897,15 @@
qp = self.qparents(repo, rev)
changes = repo.changelog.read(qp)
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), mmap.execf[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
@@ -917,9 +927,9 @@
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=files)
- def refresh(self, repo, msg=None, short=False):
+ def refresh(self, repo, msg='', short=False):
if len(self.applied) == 0:
self.ui.write("No patches applied\n")
return
@@ -958,30 +968,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)
+ mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
if short:
- filelist = cc + aa + dd
+ 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
@@ -992,23 +1002,23 @@
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 = list(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)
repo.dirstate.update(a, 'a')
repo.dirstate.update(r, 'r')
- repo.dirstate.update(c, 'n')
+ repo.dirstate.update(m, 'n')
repo.dirstate.forget(forget)
if not msg:
@@ -1024,7 +1034,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)
@@ -1739,7 +1749,7 @@
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
+ match). patch is pushed if any posative guards match and no
nagative guards match.
with no arguments, default is to print current active guards.
@@ -1749,19 +1759,36 @@
when no guards active, patches with posative guards are skipped,
patches with nagative guards are pushed.
+ qselect can change guards of applied patches. it does not pop
+ guarded patches by default. use --pop to pop back to last applied
+ patch that is not guarded. use --reapply (implies --pop) to push
+ back to current patch afterwards, but skip guarded patches.
+
use -s/--series to print list of all guards in 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
@@ -1789,9 +1816,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
@@ -1813,8 +1882,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]'),
@@ -1906,8 +1976,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'),
@@ -1922,4 +1995,3 @@
"qtop": (top, [], 'hg qtop'),
"qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
}
-
--- a/hgext/notify.py Mon Aug 14 14:14:08 2006 -0500
+++ b/hgext/notify.py Mon Aug 14 14:42:15 2006 -0500
@@ -67,7 +67,7 @@
from mercurial.demandload import *
from mercurial.i18n import gettext as _
from mercurial.node import *
-demandload(globals(), 'email.Parser mercurial:commands,templater,util')
+demandload(globals(), 'email.Parser mercurial:commands,patch,templater,util')
demandload(globals(), 'fnmatch socket time')
# template for single changeset can include email headers.
@@ -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/mercurial/archival.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/archival.py Mon Aug 14 14:42:15 2006 -0500
@@ -163,11 +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()
- 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, mf.execf(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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/bdiff.c Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/changelog.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:42:15 2006 -0500
@@ -0,0 +1,111 @@
+# commands.py - command processing for 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(), '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 addremove(repo, pats=[], opts={}, wlock=None, dry_run=None):
+ if dry_run is None:
+ dry_run = opts.get('dry_run')
+ add, remove = [], []
+ for src, abs, rel, exact in walk(repo, pats, opts):
+ if src == 'f' and repo.dirstate.state(abs) == '?':
+ add.append(abs)
+ 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)
+ 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)
--- a/mercurial/commands.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/commands.py Mon Aug 14 14:42:15 2006 -0500
@@ -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:
@@ -344,63 +312,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 +364,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)
@@ -577,7 +420,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 +476,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"
@@ -787,7 +630,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)
@@ -812,22 +655,7 @@
"""
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)
+ return cmdutil.addremove(repo, pats, opts)
def annotate(ui, repo, *pats, **opts):
"""show changeset information per file line
@@ -870,7 +698,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 +751,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 +762,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)
@@ -1037,8 +866,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 +930,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 +1088,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))
@@ -1476,7 +1305,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 +1334,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=ui.diffopts(opts))
def export(ui, repo, *changesets, **opts):
"""dump the header and diffs for one or more changesets
@@ -1566,15 +1368,13 @@
"""
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=ui.diffopts(opts))
def forget(ui, repo, *pats, **opts):
"""don't add the specified files on the next commit (DEPRECATED)
@@ -1587,7 +1387,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 +1444,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,10 +1510,12 @@
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
matches.clear()
+ copies.clear()
elif st == 'add':
change = repo.changelog.read(repo.lookup(str(rev)))
mf = repo.manifest.read(change[0])
@@ -1708,22 +1524,34 @@
if fn in skip:
continue
fstate.setdefault(fn, {})
+ copies.setdefault(rev, {})
try:
grepbody(fn, rev, getfile(fn).read(mf[fn]))
+ if follow:
+ copied = getfile(fn).renamed(mf[fn])
+ if copied:
+ copies[rev][fn] = copied[0]
except KeyError:
pass
elif st == 'iter':
states = matches[rev].items()
states.sort()
for fn, m in states:
+ copy = copies[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 +1560,8 @@
for fn, state in fstate:
if fn in skip:
continue
- display(fn, rev, {}, state)
+ if fn not in copies[prev[fn]]:
+ display(fn, rev, {}, state)
return (count == 0 and 1) or 0
def heads(ui, repo, **opts):
@@ -1770,7 +1599,7 @@
return
hexfunc = ui.verbose and hex or short
- modified, added, removed, deleted, unknown = repo.changes()
+ 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 +1643,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 +1671,46 @@
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)
+ files = patch.patch(strip, tmpname, ui, cwd=repo.root)
+ removes = []
if len(files) > 0:
- cfiles = files
+ cfiles = files.keys()
+ copies = []
+ copts = {'after': False, 'force': False}
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)
+ cfiles = [util.pathto(cwd, f) for f in files.keys()]
+ for f in files:
+ ctype, gp = files[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:
+ absdst = os.path.join(repo.root, dst)
+ if not after and os.path.exists(absdst):
+ raise util.Abort(_('patch creates existing file %s') % dst)
+ if cwd:
+ src, dst = [util.pathto(cwd, f) for f in (src, dst)]
+ copts['after'] = after
+ errs, copied = docopy(ui, repo, (src, dst), copts, wlock=wlock)
+ if errs:
+ raise util.Abort(errs)
+ if removes:
+ repo.remove(removes, True, wlock=wlock)
+ for f in files:
+ ctype, gp = files[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 = files.keys()
+ files.extend([r for r in removes if r not in files])
+ repo.commit(files, message, user, date, wlock=wlock, lock=lock)
finally:
os.unlink(tmpname)
@@ -1964,7 +1763,7 @@
displayer.show(changenode=n)
if opts['patch']:
prev = (parents and parents[0]) or nullid
- dodiff(ui, ui, other, prev, n)
+ patch.diff(repo, other, prev, n)
ui.write("\n")
finally:
if hasattr(other, 'close'):
@@ -2012,8 +1811,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 +1914,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
@@ -2196,7 +1995,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 +2208,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')
@@ -2521,20 +2320,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 +2541,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]
@@ -2844,7 +2644,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
@@ -3091,6 +2891,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 +2929,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', '',
@@ -3202,7 +3004,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]')),
@@ -3545,6 +3347,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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/context.py Mon Aug 14 14:42:15 2006 -0500
@@ -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/dirstate.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/dirstate.py Mon Aug 14 14:42:15 2006 -0500
@@ -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.
--- a/mercurial/filelog.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/filelog.py Mon Aug 14 14:42:15 2006 -0500
@@ -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.
--- a/mercurial/hg.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/hg.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/hgweb/common.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/hgweb/hgweb_mod.py Mon Aug 14 14:42:15 2006 -0500
@@ -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.
@@ -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 = ui.diffopts()
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.read(mfn).execf[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.read(mfn).execf[f])
+ permissions=self.repo.manifest.read(mfn).execf(f))
def manifest(self, mnode, path):
man = self.repo.manifest
@@ -495,7 +485,7 @@
"filenode": hex(fnode),
"parity": self.stripes(parity),
"basename": f,
- "permissions": mf.execf[full]}
+ "permissions": mf.execf(full)}
parity += 1
def dirlist(**map):
--- a/mercurial/hgweb/hgwebdir_mod.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/hgweb/hgwebdir_mod.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/hgweb/request.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/hgweb/server.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/httprangereader.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/httprepo.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/i18n.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/localrepo.py Mon Aug 14 14:42:15 2006 -0500
@@ -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.
@@ -198,7 +198,7 @@
self.hook('tag', node=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)'))
@@ -502,7 +502,6 @@
except IOError:
try:
del m1[f]
- del m1[f]
if update_dirstate:
self.dirstate.forget([f])
except:
@@ -533,7 +532,7 @@
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
@@ -752,16 +751,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()
--- a/mercurial/lock.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/lock.py Mon Aug 14 14:42:15 2006 -0500
@@ -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.
--- a/mercurial/manifest.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/manifest.py Mon Aug 14 14:42:15 2006 -0500
@@ -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.
@@ -11,7 +11,9 @@
demandload(globals(), "array bisect struct")
class manifestdict(dict):
- def __init__(self, mapping={}, flags={}):
+ 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):
@@ -27,8 +29,9 @@
fl = entry[40:-1]
if fl: self._flags[f] = fl
def set(self, f, execf=False, linkf=False):
- if execf: self._flags[f] = "x"
- if linkf: self._flags[f] = "x"
+ 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))
--- a/mercurial/mdiff.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/mdiff.py Mon Aug 14 14:42:15 2006 -0500
@@ -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,39 @@
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
+ 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,
+ '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 +74,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 +94,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 +117,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 +135,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 +175,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 +189,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 +200,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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/merge.py Mon Aug 14 14:42:15 2006 -0500
@@ -75,7 +75,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"))
--- a/mercurial/mpatch.c Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/mpatch.c Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/node.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/packagescan.py Mon Aug 14 14:42:15 2006 -0500
@@ -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.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/patch.py Mon Aug 14 14:42:15 2006 -0500
@@ -0,0 +1,365 @@
+# 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 os re shutil sys tempfile")
+
+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
+
+ if os.path.exists(p.path):
+ raise util.Abort(_("cannot create %s: destination already exists") %
+ p.path)
+
+ (src, dst) = [os.path.join(os.getcwd(), n)
+ for n in (p.oldpath, p.path)]
+
+ targetdir = os.path.dirname(dst)
+ if not os.path.isdir(targetdir):
+ os.makedirs(targetdir)
+ try:
+ shutil.copyfile(src, dst)
+ shutil.copymode(src, dst)
+ except shutil.Error, inst:
+ raise util.Abort(str(inst))
+
+ # 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(strip, patchname, ui, cwd=None):
+ """apply the patch <patchname> to the working directory.
+ a list of patched files is returned"""
+
+ (dopatch, gitpatches) = readgitpatch(patchname)
+
+ files = {}
+ 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.status("%s\n" % line)
+ if line.startswith('patching file '):
+ pf = util.parse_patch_output(line)
+ files.setdefault(pf, (None, None))
+ 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
+
+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]
+ # reading the data for node1 early allows it to play nicely
+ # with repo.status 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.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
+
+ 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 repo.ui.quiet:
+ r = None
+ else:
+ hexfunc = repo.ui.verbose and hex or short
+ r = [hexfunc(node) for node in [node1, node2] if node]
+
+ 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, 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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/remoterepo.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/repo.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/revlog.py Mon Aug 14 14:42:15 2006 -0500
@@ -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.
--- a/mercurial/sshrepo.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/sshrepo.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/sshserver.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/statichttprepo.py Mon Aug 14 14:42:15 2006 -0500
@@ -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.
--- a/mercurial/templater.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/templater.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/transaction.py Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/ui.py Mon Aug 14 14:42:15 2006 -0500
@@ -1,6 +1,6 @@
# 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.
@@ -8,7 +8,7 @@
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(), "ConfigParser mdiff templater traceback util")
class ui(object):
def __init__(self, verbose=False, debug=False, quiet=False,
@@ -169,16 +169,17 @@
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 diffopts(self, opts={}):
+ return mdiff.diffopts(
+ text=opts.get('text'),
+ showfunc=(opts.get('show_function') or
+ self.configbool('diff', 'showfunc', None)),
+ ignorews=(opts.get('ignore_all_space') or
+ self.configbool('diff', 'ignorews', None)),
+ ignorewsamount=(opts.get('ignore_space_change') or
+ self.configbool('diff', 'ignorewsamount', None)),
+ ignoreblanklines=(opts.get('ignore_blank_lines') or
+ self.configbool('diff', 'ignoreblanklines', None)))
def username(self):
"""Return default username to be used in commits.
--- a/mercurial/util.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/util.py Mon Aug 14 14:42:15 2006 -0500
@@ -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]:
@@ -1014,3 +995,4 @@
if path.startswith('//'):
path = path[2:]
return path
+
--- a/mercurial/version.py Mon Aug 14 14:14:08 2006 -0500
+++ b/mercurial/version.py Mon Aug 14 14:42:15 2006 -0500
@@ -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/test-abort-checkin Mon Aug 14 14:14:08 2006 -0500
+++ b/tests/test-abort-checkin Mon Aug 14 14:42:15 2006 -0500
@@ -3,6 +3,11 @@
HGRCPATH=$HGTMP/.hgrc; export HGRCPATH
echo "[extensions]" >> $HGTMP/.hgrc
echo "mq=" >> $HGTMP/.hgrc
+cat > $HGTMP/false <<EOF
+#!/bin/sh
+exit 1
+EOF
+chmod +x $HGTMP/false
hg init foo
cd foo
@@ -11,7 +16,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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-diff-subdir Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:42:15 2006 -0500
@@ -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-git-import Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:42:15 2006 -0500
@@ -0,0 +1,39 @@
+% new file
+applying patch from stdin
+patching file new
+% 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
+patching file copyx
+new
+rename
+% regular diff
+applying patch from stdin
+patching file rename
+% copy and modify
+applying patch from stdin
+patching file copy2
+a
+a
+b
+a
+a
+% rename and modify
+applying patch from stdin
+patching file rename2
+copy2: No such file or directory
+a
+a
+b
+c
+a
--- a/tests/test-globalopts Mon Aug 14 14:14:08 2006 -0500
+++ b/tests/test-globalopts Mon Aug 14 14:42:15 2006 -0500
@@ -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-grep Mon Aug 14 14:14:08 2006 -0500
+++ b/tests/test-grep Mon Aug 14 14:42:15 2006 -0500
@@ -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 Mon Aug 14 14:14:08 2006 -0500
+++ b/tests/test-grep.out Mon Aug 14 14:42:15 2006 -0500
@@ -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-import Mon Aug 14 14:14:08 2006 -0500
+++ b/tests/test-import Mon Aug 14 14:42:15 2006 -0500
@@ -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-mq Mon Aug 14 14:14:08 2006 -0500
+++ b/tests/test-mq Mon Aug 14 14:42:15 2006 -0500
@@ -10,6 +10,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 +52,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,9 +107,19 @@
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
--- a/tests/test-mq-guards Mon Aug 14 14:14:08 2006 -0500
+++ b/tests/test-mq-guards Mon Aug 14 14:42:15 2006 -0500
@@ -63,22 +63,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 Mon Aug 14 14:14:08 2006 -0500
+++ b/tests/test-mq-guards.out Mon Aug 14 14:42:15 2006 -0500
@@ -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
--- a/tests/test-mq-qrefresh-replace-log-message Mon Aug 14 14:14:08 2006 -0500
+++ b/tests/test-mq-qrefresh-replace-log-message Mon Aug 14 14:42:15 2006 -0500
@@ -33,7 +33,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 +46,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.out Mon Aug 14 14:14:08 2006 -0500
+++ b/tests/test-mq.out Mon Aug 14 14:42:15 2006 -0500
@@ -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