Merge with main
test-remove is still failing for status() does not return removed files in a
sorted list. We can live with this for now, a fix is coming soon.
--- a/hgext/hgk.py Fri Jul 11 14:40:44 2008 +0200
+++ b/hgext/hgk.py Sun Jul 20 20:00:02 2008 +0200
@@ -104,7 +104,8 @@
ctx = repo[n]
ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ??
for p in ctx.parents():
- ui.write("parent %s\n" % short(p.node()))
+ ui.write("parent %s\n" % p)
+
date = ctx.date()
description = ctx.description().replace("\0", "")
lines = description.splitlines()
--- a/mercurial/context.py Fri Jul 11 14:40:44 2008 +0200
+++ b/mercurial/context.py Sun Jul 20 20:00:02 2008 +0200
@@ -472,13 +472,9 @@
self._date = util.parsedate(date)
else:
self._date = util.makedate()
- if user:
- self._user = user
- else:
- self._user = self._repo.ui.username()
+ self._user = user
if parents:
- p1, p2 = parents
- self._parents = [changectx(self._repo, p) for p in (p1, p2)]
+ self._parents = [changectx(self._repo, p) for p in parents]
if changes:
self._status = list(changes)
@@ -501,6 +497,9 @@
def __nonzero__(self):
return True
+ def __contains__(self, key):
+ return self._dirstate[f] not in "?r"
+
def __getattr__(self, name):
if name == '_status':
self._status = self._repo.status(unknown=True)
@@ -541,7 +540,7 @@
def manifest(self): return self._manifest
- def user(self): return self._user
+ def user(self): return self._user or self._repo.ui.username()
def date(self): return self._date
def description(self): return self._text
def files(self):
@@ -701,7 +700,7 @@
self._node = None
self._text = text
self._date = date and util.parsedate(date) or util.makedate()
- self._user = user or self._repo.ui.username()
+ self._user = user
parents = [(p or nullid) for p in parents]
p1, p2 = parents
self._parents = [changectx(self._repo, p) for p in (p1, p2)]
@@ -724,7 +723,7 @@
def __nonzero__(self):
return True
- def user(self): return self._user
+ def user(self): return self._user or self._repo.ui.username()
def date(self): return self._date
def description(self): return self._text
def files(self): return self.modified()
--- a/mercurial/dirstate.py Fri Jul 11 14:40:44 2008 +0200
+++ b/mercurial/dirstate.py Sun Jul 20 20:00:02 2008 +0200
@@ -9,12 +9,20 @@
from node import nullid
from i18n import _
-import struct, os, bisect, stat, strutil, util, errno, ignore
+import struct, os, bisect, stat, util, errno, ignore
import cStringIO, osutil, sys
_unknown = ('?', 0, 0, 0)
_format = ">cllll"
+def _finddirs(path):
+ pos = len(path)
+ while 1:
+ pos = path.rfind('/', 0, pos)
+ if pos == -1:
+ break
+ yield path[:pos]
+
class dirstate(object):
def __init__(self, opener, ui, root):
@@ -55,10 +63,12 @@
if err.errno != errno.ENOENT: raise
return self._pl
elif name == '_dirs':
- self._dirs = {}
- for f in self._map:
- if self[f] != 'r':
- self._incpath(f)
+ dirs = {}
+ for f,s in self._map.items():
+ if s[0] != 'r':
+ for base in _finddirs(f):
+ dirs[base] = dirs.get(base, 0) + 1
+ self._dirs = dirs
return self._dirs
elif name == '_ignore':
files = [self._join('.hgignore')]
@@ -223,67 +233,39 @@
def copies(self):
return self._copymap
- def _incpath(self, path):
- c = path.rfind('/')
- if c >= 0:
+ def _droppath(self, f):
+ if self[f] not in "?r" and "_dirs" in self.__dict__:
dirs = self._dirs
- base = path[:c]
- if base not in dirs:
- self._incpath(base)
- dirs[base] = 1
- else:
- dirs[base] += 1
-
- def _decpath(self, path):
- c = path.rfind('/')
- if c >= 0:
- base = path[:c]
- dirs = self._dirs
- if dirs[base] == 1:
- del dirs[base]
- self._decpath(base)
- else:
- dirs[base] -= 1
+ for base in _finddirs(f):
+ if dirs[base] == 1:
+ del dirs[base]
+ else:
+ dirs[base] -= 1
- def _incpathcheck(self, f):
- if '\r' in f or '\n' in f:
- raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r")
- % f)
- # shadows
- if f in self._dirs:
- raise util.Abort(_('directory %r already in dirstate') % f)
- for c in strutil.rfindall(f, '/'):
- d = f[:c]
- if d in self._dirs:
- break
- if d in self._map and self[d] != 'r':
- raise util.Abort(_('file %r in dirstate clashes with %r') %
- (d, f))
- self._incpath(f)
-
- def _changepath(self, f, newstate, relaxed=False):
- # handle upcoming path changes
+ def _addpath(self, f, check=False):
oldstate = self[f]
- if oldstate not in "?r" and newstate in "?r":
- if "_dirs" in self.__dict__:
- self._decpath(f)
- return
- if oldstate in "?r" and newstate not in "?r":
- if relaxed and oldstate == '?':
- # XXX
- # in relaxed mode we assume the caller knows
- # what it is doing, workaround for updating
- # dir-to-file revisions
- if "_dirs" in self.__dict__:
- self._incpath(f)
- return
- self._incpathcheck(f)
- return
+ if check or oldstate == "r":
+ if '\r' in f or '\n' in f:
+ raise util.Abort(
+ _("'\\n' and '\\r' disallowed in filenames: %r") % f)
+ if f in self._dirs:
+ raise util.Abort(_('directory %r already in dirstate') % f)
+ # shadows
+ for d in _finddirs(f):
+ if d in self._dirs:
+ break
+ if d in self._map and self[d] != 'r':
+ raise util.Abort(
+ _('file %r in dirstate clashes with %r') % (d, f))
+ if oldstate in "?r" and "_dirs" in self.__dict__:
+ dirs = self._dirs
+ for base in _finddirs(f):
+ dirs[base] = dirs.get(base, 0) + 1
def normal(self, f):
'mark a file normal and clean'
self._dirty = True
- self._changepath(f, 'n', True)
+ self._addpath(f)
s = os.lstat(self._join(f))
self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime, 0)
if f in self._copymap:
@@ -307,7 +289,7 @@
if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
return
self._dirty = True
- self._changepath(f, 'n', True)
+ self._addpath(f)
self._map[f] = ('n', 0, -1, -1, 0)
if f in self._copymap:
del self._copymap[f]
@@ -315,7 +297,7 @@
def normaldirty(self, f):
'mark a file normal, but dirty'
self._dirty = True
- self._changepath(f, 'n', True)
+ self._addpath(f)
self._map[f] = ('n', 0, -2, -1, 0)
if f in self._copymap:
del self._copymap[f]
@@ -323,7 +305,7 @@
def add(self, f):
'mark a file added'
self._dirty = True
- self._changepath(f, 'a')
+ self._addpath(f, True)
self._map[f] = ('a', 0, -1, -1, 0)
if f in self._copymap:
del self._copymap[f]
@@ -331,7 +313,7 @@
def remove(self, f):
'mark a file removed'
self._dirty = True
- self._changepath(f, 'r')
+ self._droppath(f)
size = 0
if self._pl[1] != nullid and f in self._map:
entry = self._map[f]
@@ -347,7 +329,7 @@
'mark a file merged'
self._dirty = True
s = os.lstat(self._join(f))
- self._changepath(f, 'm', True)
+ self._addpath(f)
self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime, 0)
if f in self._copymap:
del self._copymap[f]
@@ -356,7 +338,7 @@
'forget a file'
self._dirty = True
try:
- self._changepath(f, '?')
+ self._droppath(f)
del self._map[f]
except KeyError:
self._ui.warn(_("not in dirstate: %s\n") % f)
@@ -467,8 +449,8 @@
return False
if self._ignore(f):
return True
- for c in strutil.findall(f, '/'):
- if self._ignore(f[:c]):
+ for p in _finddirs(f):
+ if self._ignore(p):
return True
return False
@@ -606,7 +588,7 @@
known[nn] = 1
if match(nf):
if supported(ff, st.st_mode, verbose=True):
- yield 'f', self.normalize(nf), st
+ yield 'f', nn, st
elif ff in dc:
yield 'm', nf, st
--- a/mercurial/help.py Fri Jul 11 14:40:44 2008 +0200
+++ b/mercurial/help.py Sun Jul 20 20:00:02 2008 +0200
@@ -21,7 +21,7 @@
"13:18" (today assumed)
"3:39" (3:39AM assumed)
"3:39pm" (15:39)
- "2006-12-6 13:18:29" (ISO 8601 format)
+ "2006-12-06 13:18:29" (ISO 8601 format)
"2006-12-6 13:18"
"2006-12-6"
"12-6"
--- a/mercurial/localrepo.py Fri Jul 11 14:40:44 2008 +0200
+++ b/mercurial/localrepo.py Sun Jul 20 20:00:02 2008 +0200
@@ -943,7 +943,7 @@
'''
return self[node].walk(match)
- def status(self, node1=None, node2=None, match=None,
+ def status(self, node1='.', node2=None, match=None,
ignored=False, clean=False, unknown=False):
"""return status of files between two nodes or node and working directory
@@ -951,111 +951,84 @@
If node2 is None, compare node1 with working directory.
"""
- def fcmp(fn, getnode):
- t1 = self.wread(fn)
- return self.file(fn).cmp(getnode(fn), t1)
-
- def mfmatches(node):
- change = self.changelog.read(node)
- mf = self.manifest.read(change[0]).copy()
+ def mfmatches(ctx):
+ mf = ctx.manifest().copy()
for fn in mf.keys():
if not match(fn):
del mf[fn]
return mf
- if not match:
- match = match_.always(self.root, self.getcwd())
-
+ ctx1 = self[node1]
+ ctx2 = self[node2]
+ working = ctx2 == self[None]
+ parentworking = working and ctx1 == self['.']
+ match = match or match_.always(self.root, self.getcwd())
listignored, listclean, listunknown = ignored, clean, unknown
- modified, added, removed, deleted, unknown = [], [], [], [], []
- ignored, clean = [], []
- compareworking = False
- if not node1 or (not node2 and node1 == self.dirstate.parents()[0]):
- compareworking = True
-
- if not compareworking:
- # read the manifest from node1 before the manifest from node2,
- # so that we'll hit the manifest cache if we're going through
- # all the revisions in parent->child order.
- mf1 = mfmatches(node1)
+ if working: # we need to scan the working dir
+ s = self.dirstate.status(match, listignored, listclean, listunknown)
+ cmp, modified, added, removed, deleted, unknown, ignored, clean = s
- # are we comparing the working directory?
- if not node2:
- (lookup, modified, added, removed, deleted, unknown,
- ignored, clean) = self.dirstate.status(match, listignored,
- listclean, listunknown)
- # are we comparing working dir against its parent?
- if compareworking:
- if lookup:
- fixup = []
- # do a full compare of any files that might have changed
- ctx = self['.']
- ff = self.dirstate.flagfunc(ctx.flags)
- for f in lookup:
- if (f not in ctx or ff(f) != ctx.flags(f)
- or ctx[f].cmp(self.wread(f))):
- modified.append(f)
- else:
- fixup.append(f)
- if listclean:
- clean.append(f)
+ # check for any possibly clean files
+ if parentworking and cmp:
+ fixup = []
+ # do a full compare of any files that might have changed
+ for f in cmp:
+ if (f not in ctx1 or ctx2.flags(f) != ctx1.flags(f)
+ or ctx1[f].cmp(ctx2[f].data())):
+ modified.append(f)
+ else:
+ fixup.append(f)
+
+ modified.sort()
+ if listclean:
+ clean = util.sort(clean + fixup)
- # update dirstate for files that are actually clean
- if fixup:
- wlock = None
+ # update dirstate for files that are actually clean
+ if fixup:
+ wlock = None
+ try:
try:
- try:
- wlock = self.wlock(False)
- except lock.LockException:
- pass
- if wlock:
- for f in fixup:
- self.dirstate.normal(f)
- finally:
- del wlock
- else:
+ wlock = self.wlock(False)
+ for f in fixup:
+ self.dirstate.normal(f)
+ except lock.LockException:
+ pass
+ finally:
+ del wlock
+
+ if not parentworking:
+ mf1 = mfmatches(ctx1)
+ if working:
# we are comparing working dir against non-parent
# generate a pseudo-manifest for the working dir
- # XXX: create it in dirstate.py ?
- mf2 = mfmatches(self.dirstate.parents()[0])
- ff = self.dirstate.flagfunc(mf2.flags)
- for f in lookup + modified + added:
- mf2[f] = ""
- mf2.set(f, ff(f))
+ mf2 = mfmatches(self['.'])
+ mf2.flags = ctx2.flags # delay flag lookup
+ for f in cmp + modified + added:
+ mf2[f] = None
for f in removed:
if f in mf2:
del mf2[f]
-
- else:
- # we are comparing two revisions
- mf2 = mfmatches(node2)
+ else:
+ # we are comparing two revisions
+ deleted, unknown, ignored = [], [], []
+ mf2 = mfmatches(ctx2)
- if not compareworking:
- # flush lists from dirstate before comparing manifests
modified, added, clean = [], [], []
-
- # make sure to sort the files so we talk to the disk in a
- # reasonable order
- getnode = lambda fn: mf1.get(fn, nullid)
for fn in util.sort(mf2):
if fn in mf1:
- if (mf1.flags(fn) != mf2.flags(fn) or
- (mf1[fn] != mf2[fn] and
- (mf2[fn] != "" or fcmp(fn, getnode)))):
+ if ((mf1[fn] != mf2[fn] and
+ (mf2[fn] or ctx1[fn].cmp(ctx2[fn].data())))
+ or mf1.flags(fn) != mf2.flags(fn)):
modified.append(fn)
elif listclean:
clean.append(fn)
del mf1[fn]
else:
added.append(fn)
-
- removed = mf1.keys()
+ removed = util.sort(mf1.keys())
- # sort and return results:
- for l in modified, added, removed, deleted, unknown, ignored, clean:
- l.sort()
- return (modified, added, removed, deleted, unknown, ignored, clean)
+ return modified, added, removed, deleted, unknown, ignored, clean
def add(self, list):
wlock = self.wlock()