changeset 5827:0c29977bd7db

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.
author Kirill Smelkov <kirr@mns.spb.ru>
date Thu, 10 Jan 2008 12:07:13 +0300
parents cc43d9f36ff2
children 863e237b58fb
files hgext/record.py
diffstat 1 files changed, 37 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/record.py	Thu Jan 10 11:43:30 2008 +0300
+++ b/hgext/record.py	Thu Jan 10 12:07:13 2008 +0300
@@ -358,10 +358,29 @@
 
     ? - 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:
@@ -374,6 +393,7 @@
                    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))
         del fp
 
@@ -392,6 +412,7 @@
             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:
@@ -400,6 +421,7 @@
             if err.errno != errno.EEXIST:
                 raise
         try:
+            # backup continues
             for f in newfiles:
                 if f not in modified:
                     continue
@@ -417,19 +439,32 @@
             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!
+
+            # it is important to first chdir to repo root -- we'll call a
+            # highlevel command with list of pathnames relative to repo root
+            cwd = os.getcwd()
+            os.chdir(repo.root)
+            try:
+                committer(ui, repo, newfiles, opts)
+            finally:
+                os.chdir(cwd)
+
             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))