[PATCH 2 of 5] record: refactor record into generic record driver

Kirill Smelkov kirr at mns.spb.ru
Thu Dec 27 13:01:42 CST 2007


# HG changeset patch
# User Kirill Smelkov <kirr at mns.spb.ru>
# Date 1198781921 -10800
# Node ID 6af765f2f9e5f8c528dedc72a4f579c661040e2e
# Parent  595aec2ce35483a3508e1ee836e2d637c391c61b
record: refactor record into generic record driver

rationale
---------

I'd like to make MQ version of record -- qrecord.

>From the first glance it seemed to be easy -- the task in essence would be to
change call to cmdutil.commit() to something like mq.qrefresh().

As it turned out queue.refresh() and cmdutil.commit() have different semantics
-- cmdutil.commit() first scans for changes and then delegate the actual commit
to lowlevel func. On the other hand queue.refresh() do it all in once, and I am
a bit scary to change it.

Maybe the right way would be to first refactor queue.refresh() to use
cmdutil.commit() machinery, and then trivially adjust record, but I feel I'm
not competent for the task right now.

Instead, I propose we refactor record to be some sort of high-level driver, or
like a high-level decorator one can say, which will first interactively filter
changes, and then delegate commit job to high-level commiter, e.g. 'commit' or
'qrefresh'


So, this patch does just that -- refactor record to be generic driver, and
update 'hg record' code to use the driver.

'hg qrecord' will follow.

diff --git a/hgext/record.py b/hgext/record.py
--- a/hgext/record.py
+++ b/hgext/record.py
@@ -361,10 +361,29 @@ def record(ui, repo, *pats, **opts):
 
     ? - display help'''
 
+    def record_commiter(ui, repo, pats, opts):
+        commands.commit(ui, repo, *pats, **opts)
+
+    dorecord(ui, repo, record_commiter, *pats, **opts)
+
+
+def dorecord(ui, repo, committer, *pats, **opts):
     if not ui.interactive:
         raise util.Abort(_('running non-interactively, use commit instead'))
 
     def recordfunc(ui, repo, files, message, match, opts):
+        """This is generic record driver.
+
+        It's job is to interactively filter local changes, and accordingly
+        prepare working dir into a state, where the job can be delegated to
+        non-interactive commit command such as 'commit' or 'qrefresh'.
+
+        After the actual job is done by non-interactive command, working dir
+        state is restored to original.
+
+        In the end we'll record intresting changes, and everything else will be
+        left in place, so the user can continue his work.
+        """
         if files:
             changes = None
         else:
@@ -377,6 +396,7 @@ def record(ui, repo, *pats, **opts):
                    match=match, changes=changes, opts=diffopts, fp=fp)
         fp.seek(0)
 
+        # 1. filter patch, so we have intending-to apply subset of it
         chunks = filterpatch(ui, parsepatch(fp), opts)
         del fp
 
@@ -395,6 +415,7 @@ def record(ui, repo, *pats, **opts):
             changes = repo.status(files=newfiles, match=match)[:5]
         modified = dict.fromkeys(changes[0])
 
+        # 2. backup changed files, so we can restore them in the end
         backups = {}
         backupdir = repo.join('record-backups')
         try:
@@ -403,6 +424,7 @@ def record(ui, repo, *pats, **opts):
             if err.errno != errno.EEXIST:
                 raise
         try:
+            # backup continues
             for f in newfiles:
                 if f not in modified:
                     continue
@@ -420,19 +442,24 @@ def record(ui, repo, *pats, **opts):
             dopatch = fp.tell()
             fp.seek(0)
 
+            # 3a. apply filtered patch to clean repo  (clean)
             if backups:
                 hg.revert(repo, repo.dirstate.parents()[0], backups.has_key)
 
+            # 3b. (apply)
             if dopatch:
                 ui.debug('applying patch\n')
                 ui.debug(fp.getvalue())
                 patch.internalpatch(fp, ui, 1, repo.root)
             del fp
 
-            repo.commit(newfiles, message, opts['user'], opts['date'], match,
-                        force_editor=opts.get('force_editor'))
+            # 4. We prepared working directory according to filtered patch.
+            #    Now is the time to delegate the job to commit/qrefresh or the like!
+            committer(ui, repo, newfiles, opts)
+
             return 0
         finally:
+            # 5. finally restore backed-up files
             try:
                 for realname, tmpname in backups.iteritems():
                     ui.debug('restoring %r to %r\n' % (tmpname, realname))


More information about the Mercurial-devel mailing list