changeset 4948:6fd953d5faea

dirstate: break update into separate functions
author Matt Mackall <mpm@selenic.com>
date Sat, 21 Jul 2007 16:02:09 -0500
parents 81078e177266
children fc61495ea9cf
files hgext/convert/hg.py hgext/mq.py mercurial/commands.py mercurial/dirstate.py mercurial/localrepo.py mercurial/merge.py
diffstat 6 files changed, 101 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/convert/hg.py
+++ b/hgext/convert/hg.py
@@ -27,7 +27,7 @@ class convert_mercurial(converter_sink):
     def putfile(self, f, e, data):
         self.repo.wwrite(f, data, e)
         if self.repo.dirstate.state(f) == '?':
-            self.repo.dirstate.update([f], "a")
+            self.repo.dirstate.add(f)
 
     def copyfile(self, source, dest):
         self.repo.copy(source, dest)
--- a/hgext/mq.py
+++ b/hgext/mq.py
@@ -501,8 +501,10 @@ class queue:
                         merged.append(f)
                     else:
                         removed.append(f)
-                repo.dirstate.update(repo.dirstate.filterfiles(removed), 'r')
-                repo.dirstate.update(repo.dirstate.filterfiles(merged), 'm')
+                for f in removed:
+                    repo.dirstate.remove(f)
+                for f in merged:
+                    repo.dirstate.merge(f)
                 p1, p2 = repo.dirstate.parents()
                 repo.dirstate.setparents(p1, merge)
             files = patch.updatedir(self.ui, repo, files, wlock=wlock)
@@ -868,7 +870,8 @@ class queue:
             for f in r:
                 getfile(f, mmap[f])
                 util.set_exec(repo.wjoin(f), mmap.execf(f))
-            repo.dirstate.update(m + r, 'n')
+            for f in m + r:
+                repo.dirstate.normal(f)
             for f in a:
                 try:
                     os.unlink(repo.wjoin(f))
@@ -877,8 +880,7 @@ class queue:
                         raise
                 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
                 except: pass
-            if a:
-                repo.dirstate.forget(a)
+                repo.dirstate.forget(f)
             repo.dirstate.setparents(qp, revlog.nullid)
         self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
         del self.applied[start:end]
@@ -1010,7 +1012,7 @@ class queue:
                 if src is None:
                     continue
                 copies.setdefault(src, []).append(dst)
-            repo.dirstate.update(a, 'a')
+                repo.dirstate.add(dst)
             # remember the copies between patchparent and tip
             # this may be slow, so don't do it if we're not tracking copies
             if self.diffopts().git:
@@ -1027,7 +1029,8 @@ class queue:
             for src, dsts in copies.iteritems():
                 for dst in dsts:
                     repo.dirstate.copy(src, dst)
-            repo.dirstate.update(r, 'r')
+            for f in r:
+                repo.dirstate.remove(f)
             # if the patch excludes a modified file, mark that file with mtime=0
             # so status can see it.
             mm = []
@@ -1035,9 +1038,12 @@ class queue:
                 if not matchfn(m[i]):
                     mm.append(m[i])
                     del m[i]
-            repo.dirstate.update(m, 'n')
-            repo.dirstate.update(mm, 'n', st_mtime=-1, st_size=-1)
-            repo.dirstate.forget(forget)
+            for f in m:
+                repo.dirstate.normal(f)
+            for f in mm:
+                repo.dirstate.normaldirty(f)
+            for f in forget:
+                repo.dirstate.forget(f)
 
             if not msg:
                 if not message:
@@ -1066,9 +1072,9 @@ class queue:
                         raise
                 try: os.removedirs(os.path.dirname(f))
                 except: pass
-            # forget the file copies in the dirstate
-            # push should readd the files later on
-            repo.dirstate.forget(added)
+                # forget the file copies in the dirstate
+                # push should readd the files later on
+                repo.dirstate.forget(a)
             self.pop(repo, force=True, wlock=wlock)
             self.push(repo, force=True, wlock=wlock)
 
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2415,11 +2415,15 @@ def revert(ui, repo, *pats, **opts):
                     handle(remove, False)
 
     if not opts.get('dry_run'):
-        repo.dirstate.forget(forget[0])
+        for f in forget[0]:
+            repo.dirstate.forget(f)
         r = hg.revert(repo, node, update.has_key, wlock)
-        repo.dirstate.update(add[0], 'a')
-        repo.dirstate.update(undelete[0], 'n')
-        repo.dirstate.update(remove[0], 'r')
+        for f in add[0]:
+            repo.dirstate.add(f)
+        for f in undelete[0]:
+            repo.dirstate.normal(f)
+        for f in remove[0]:
+            repo.dirstate.remove(f)
         return r
 
 def rollback(ui, repo):
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -118,6 +118,11 @@ class dirstate(object):
         self._opener("branch", "w").write(branch + '\n')
 
     def state(self, key):
+        ''' current states:
+        n  normal
+        m  needs merging
+        r  marked for removal
+        a  marked for addition'''
         return self._map.get(key, ("?",))[0]
 
     def _read(self):
@@ -197,41 +202,55 @@ class dirstate(object):
                 raise util.Abort(_('file named %r already in dirstate') % d)
         self._incpath(f)
 
-    def update(self, files, state, **kw):
-        ''' current states:
-        n  normal
-        m  needs merging
-        r  marked for removal
-        a  marked for addition'''
+    def normal(self, f):
+        'mark a file normal'
+        self._dirty = True
+        s = os.lstat(self.wjoin(f))
+        self._map[f] = ('n', s.st_mode, s.st_size, s.st_mtime)
+        if self._copymap.has_key(f):
+            del self._copymap[f]
 
-        if not files: return
+    def normaldirty(self, f):
+        'mark a file normal, but possibly dirty'
         self._dirty = True
-        for f in files:
-            if self._copymap.has_key(f):
-                del self._copymap[f]
+        s = os.lstat(self.wjoin(f))
+        self._map[f] = ('n', s.st_mode, -1, -1)
+        if f in self._copymap:
+            del self._copymap[f]
+
+    def add(self, f):
+        'mark a file added'
+        self._dirty = True
+        self._incpathcheck(f)
+        s = os.lstat(self.wjoin(f))
+        self._map[f] = ('a', s.st_mode, s.st_size, s.st_mtime)
+        if f in self._copymap:
+            del self._copymap[f]
 
-            if state == "r":
-                self._map[f] = ('r', 0, 0, 0)
-                self._decpath(f)
-                continue
-            else:
-                if state == "a":
-                    self._incpathcheck(f)
-                s = os.lstat(self.wjoin(f))
-                st_size = kw.get('st_size', s.st_size)
-                st_mtime = kw.get('st_mtime', s.st_mtime)
-                self._map[f] = (state, s.st_mode, st_size, st_mtime)
+    def remove(self, f):
+        'mark a file removed'
+        self._dirty = True
+        self._map[f] = ('r', 0, 0, 0)
+        self._decpath(f)
+        if f in self._copymap:
+            del self._copymap[f]
 
-    def forget(self, files):
-        if not files: return
+    def merge(self, f):
+        'mark a file merged'
         self._dirty = True
-        for f in files:
-            try:
-                del self._map[f]
-                self._decpath(f)
-            except KeyError:
-                self._ui.warn(_("not in dirstate: %s!\n") % f)
-                pass
+        s = os.lstat(self.wjoin(f))
+        self._map[f] = ('m', s.st_mode, s.st_size, s.st_mtime)
+        if f in self._copymap:
+            del self._copymap[f]
+
+    def forget(self, f):
+        'forget a file'
+        self._dirty = True
+        try:
+            del self._map[f]
+            self._decpath(f)
+        except KeyError:
+            self._ui.warn(_("not in dirstate: %s!\n") % f)
 
     def rebuild(self, parent, files):
         self.invalidate()
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -792,8 +792,10 @@ class localrepository(repo.repository):
         if use_dirstate or update_dirstate:
             self.dirstate.setparents(n)
             if use_dirstate:
-                self.dirstate.update(new, "n")
-                self.dirstate.forget(removed)
+                for f in new:
+                    self.dirstate.normal(f)
+                for f in removed:
+                    self.dirstate.forget(f)
 
         self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
         return n
@@ -901,7 +903,7 @@ class localrepository(repo.repository):
                                 except lock.LockException:
                                     pass
                             if wlock:
-                                self.dirstate.update([f], "n")
+                                self.dirstate.normal(f)
             else:
                 # we are comparing working dir against non-parent
                 # generate a pseudo-manifest for the working dir
@@ -971,7 +973,7 @@ class localrepository(repo.repository):
             elif self.dirstate.state(f) in 'an':
                 self.ui.warn(_("%s already tracked!\n") % f)
             else:
-                self.dirstate.update([f], "a")
+                self.dirstate.add(f)
 
     def forget(self, list, wlock=None):
         if not wlock:
@@ -980,7 +982,7 @@ class localrepository(repo.repository):
             if self.dirstate.state(f) not in 'ai':
                 self.ui.warn(_("%s not added!\n") % f)
             else:
-                self.dirstate.forget([f])
+                self.dirstate.forget(f)
 
     def remove(self, list, unlink=False, wlock=None):
         if unlink:
@@ -996,11 +998,11 @@ class localrepository(repo.repository):
             if unlink and os.path.exists(self.wjoin(f)):
                 self.ui.warn(_("%s still exists!\n") % f)
             elif self.dirstate.state(f) == 'a':
-                self.dirstate.forget([f])
+                self.dirstate.forget(f)
             elif f not in self.dirstate:
                 self.ui.warn(_("%s not tracked!\n") % f)
             else:
-                self.dirstate.update([f], "r")
+                self.dirstate.remove(f)
 
     def undelete(self, list, wlock=None):
         p = self.dirstate.parents()[0]
@@ -1014,7 +1016,7 @@ class localrepository(repo.repository):
             else:
                 t = self.file(f).read(m[f])
                 self.wwrite(f, t, m.flags(f))
-                self.dirstate.update([f], "n")
+                self.dirstate.normal(f)
 
     def copy(self, source, dest, wlock=None):
         p = self.wjoin(dest)
@@ -1027,7 +1029,7 @@ class localrepository(repo.repository):
             if not wlock:
                 wlock = self.wlock()
             if self.dirstate.state(dest) == '?':
-                self.dirstate.update([dest], "a")
+                self.dirstate.add(dest)
             self.dirstate.copy(source, dest)
 
     def heads(self, start=None):
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -447,25 +447,25 @@ def recordupdates(repo, action, branchme
         f, m = a[:2]
         if m == "r": # remove
             if branchmerge:
-                repo.dirstate.update([f], 'r')
+                repo.dirstate.remove(f)
             else:
-                repo.dirstate.forget([f])
+                repo.dirstate.forget(f)
         elif m == "f": # forget
-            repo.dirstate.forget([f])
+            repo.dirstate.forget(f)
         elif m == "g": # get
             if branchmerge:
-                repo.dirstate.update([f], 'n', st_mtime=-1)
+                repo.dirstate.normaldirty(f)
             else:
-                repo.dirstate.update([f], 'n')
+                repo.dirstate.normal(f)
         elif m == "m": # merge
             f2, fd, flag, move = a[2:]
             if branchmerge:
                 # We've done a branch merge, mark this file as merged
                 # so that we properly record the merger later
-                repo.dirstate.update([fd], 'm')
+                repo.dirstate.merge(fd)
                 if f != f2: # copy/rename
                     if move:
-                        repo.dirstate.update([f], 'r')
+                        repo.dirstate.remove(f)
                     if f != fd:
                         repo.dirstate.copy(f, fd)
                     else:
@@ -476,25 +476,25 @@ def recordupdates(repo, action, branchme
                 # of that file some time in the past. Thus our
                 # merge will appear as a normal local file
                 # modification.
-                repo.dirstate.update([fd], 'n', st_size=-1, st_mtime=-1)
+                repo.dirstate.normaldirty(fd)
                 if move:
-                    repo.dirstate.forget([f])
+                    repo.dirstate.forget(f)
         elif m == "d": # directory rename
             f2, fd, flag = a[2:]
             if not f2 and f not in repo.dirstate:
                 # untracked file moved
                 continue
             if branchmerge:
-                repo.dirstate.update([fd], 'a')
+                repo.dirstate.add(fd)
                 if f:
-                    repo.dirstate.update([f], 'r')
+                    repo.dirstate.remove(f)
                     repo.dirstate.copy(f, fd)
                 if f2:
                     repo.dirstate.copy(f2, fd)
             else:
-                repo.dirstate.update([fd], 'n')
+                repo.dirstate.normal(fd)
                 if f:
-                    repo.dirstate.forget([f])
+                    repo.dirstate.forget(f)
 
 def update(repo, node, branchmerge, force, partial, wlock):
     """