[PATCH 3 of 5] localrepo: add memcommit() to commit without working directory
Patrick Mezard
pmezard at gmail.com
Mon Jun 2 16:31:38 CDT 2008
# HG changeset patch
# User Patrick Mezard <pmezard at gmail.com>
# Date 1212441833 -7200
# Node ID 50a52215368f4127b5fe720ad49ad214a9ddf8de
# Parent 994a2a32961411354900a07bdb4a7f50ddc3a01d
localrepo: add memcommit() to commit without working directory
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -12,6 +12,23 @@
import lock, transaction, stat, errno, ui
import os, revlog, time, util, extensions, hook, inspect
import match as match_
+
+class fileobject:
+ def name(self):
+ raise NotImplementedError()
+ def data(self):
+ """Return the file raw data, no filters are applied when
+ committed. Raise IOError or OSError if the file does not
+ exist.
+ """
+ raise NotImplementedError()
+ def islink(self):
+ return False
+ def isexec(self):
+ return False
+ def copied(self):
+ """Return the manifest name of the copied file or None."""
+ return None
class localrepository(repo.repository):
capabilities = util.set(('lookup', 'changegroupsubset'))
@@ -931,6 +948,110 @@
self.dirstate.invalidate()
del tr, lock, wlock
+ def memcommit(self, files=[], text="", user=None, date=None,
+ p1=None, p2=None, extra={}):
+ """Commit directly without relying on the working directory.
+
+ files is be a list of fileobject instances.
+ """
+ wlock = lock = tr = None
+ valid = 0 # don't save the dirstate if this isn't set
+
+ fileobjs = {}
+ for f in files:
+ if f.name() in fileobjs:
+ raise util.Abort(_("%s appears twice in commit list!"))
+ fileobjs[f.name()] = f
+ files = list(files)
+ files.sort(lambda a,b: cmp(a.name(), b.name()))
+
+ try:
+ wlock = self.wlock()
+ lock = self.lock()
+
+ p1, p2 = p1, p2 or nullid
+ update_dirstate = (self.dirstate.parents()[0] == p1)
+
+ c1 = self.changelog.read(p1)
+ c2 = self.changelog.read(p2)
+ m1 = self.manifest.read(c1[0]).copy()
+ m2 = self.manifest.read(c2[0])
+
+ xp1 = hex(p1)
+ if p2 == nullid: xp2 = ''
+ else: xp2 = hex(p2)
+
+ tr = self.transaction()
+ trp = weakref.proxy(tr)
+
+ # check in files
+ new = {}
+ remove = []
+ changed = []
+ linkrev = self.changelog.count()
+ for fobj in files:
+ f = fobj.name()
+ self.ui.note(f + "\n")
+ try:
+ new[f] = self.filecommit(f, fobj.data(), fobj.copied(), m1,
+ m2, linkrev, trp, changed)
+ new_exec = fobj.isexec()
+ new_link = fobj.islink()
+ if ((not changed or changed[-1] != f) and
+ m2.get(f) != new[f]):
+ # mention the file in the changelog if some
+ # flag changed, even if there was no content
+ # change.
+ old_exec = m1.execf(f)
+ old_link = m1.linkf(f)
+ if old_exec != new_exec or old_link != new_link:
+ changed.append(f)
+ m1.set(f, new_exec, new_link)
+ except (OSError, IOError):
+ remove.append(f)
+
+ # update manifest
+ m1.update(new)
+ remove.sort()
+ removed = []
+
+ for f in remove:
+ if f in m1:
+ del m1[f]
+ removed.append(f)
+ elif f in m2:
+ removed.append(f)
+ mn = self.manifest.add(m1, trp, linkrev, c1[0], c2[0],
+ (new, removed))
+
+ # add changeset
+ user = user or self.ui.username()
+
+ lines = [line.rstrip() for line in text.rstrip().splitlines()]
+ while lines and not lines[0]:
+ del lines[0]
+ text = '\n'.join(lines)
+
+ n = self.changelog.add(mn, changed + removed, text, trp, p1, p2,
+ user, date, extra.copy())
+ self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
+ parent2=xp2)
+ tr.close()
+
+ if self.branchcache:
+ self.branchtags()
+
+ if update_dirstate:
+ self.dirstate.setparents(n)
+ valid = 1 # our dirstate updates are complete
+
+ self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
+ return n
+ finally:
+ if not valid: # don't save our updated dirstate
+ self.dirstate.invalidate()
+ del tr, lock, wlock
+
def walk(self, match, node=None):
'''
walk recursively through the directory tree or a given
More information about the Mercurial-devel
mailing list