Merge with main
authorPatrick Mezard <pmezard@gmail.com>
Sun, 20 Jul 2008 20:00:02 +0200
changeset 6812 fdf5980bd010
parent 6806 2134d6c09432 (current diff)
parent 6811 70ecce68df7c (diff)
child 6816 d8159dd15db3
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.
hgext/hgk.py
--- 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()