Patchwork [3,of,4,RFC] transaction: add a validation stage

mail settings
Submitter Pierre-Yves David
Date March 10, 2015, 8:07 a.m.
Message ID <>
Download mbox | patch
Permalink /patch/7962/
State Superseded
Commit ef22cfff705254834c454b347385f1cbdae010c7
Headers show


Pierre-Yves David - March 10, 2015, 8:07 a.m.
# HG changeset patch
# User Pierre-Yves David <>
# Date 1425966216 25200
#      Mon Mar 09 22:43:36 2015 -0700
# Node ID d3bb13fe8ffe090f13b6f66cf437333c468c8b0a
# Parent  b9b9d81a2ad56ca8951ed8c11c06bc965164120a
transaction: add a validation stage

The 'transaction' object can now be fed a 'validator' function. This function
will be run right before the transaction is closed to validate its content. The
target usage is hooks. The validation function is expected to raise an exception
when it wants to abort the transaction.

This only introduce the idea with a default no-op validator. Actual usage is in
the next changeset.


diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -810,15 +810,13 @@  variables it is passed are listed with n
   Run before any new repository transaction is open. Reason for the transaction
   opening will be in ``$HG_TXNNAME``. This hook can abort transaction opening.
-  Run right before that transaction is actually commited for good. Any
-  repository change will be visible to the hook program. This lets you validate
-  the transaction content or changes it. Exit status 0 allows the commit to
-  proceed. Non-zero status will cause the transaction to be rolled back. Reason
+  Run after any transaction have been commited. The transaction cannot be
+  aborted at this point. The hook will run after the lock is released. Reason
   for the transaction opening will be in ``$HG_TXNNAME``. The rest of the
   available data will vary according the event who append during the
   transaction. New changesets will add ``$HG_NODE`` (id of the first added
   changesets, ``$HG_URL`` and ``$HG_SOURCE`` variables, bookmark and phases
   changes will set ``HG_BOOKMARK_MOVED`` and ``HG_PHASES_MOVED`` to ``1``, etc
diff --git a/mercurial/ b/mercurial/
--- a/mercurial/
+++ b/mercurial/
@@ -81,11 +81,11 @@  def _playback(journal, report, opener, v
         # only pure backup file remains, it is sage to ignore any error
 class transaction(object):
     def __init__(self, report, opener, vfsmap, journalname, undoname=None,
-                 after=None, createmode=None):
+                 after=None, createmode=None, validator=None):
         """Begin a new transaction
         Begins a new transaction that allows rolling back writes in the event of
         an exception.
@@ -105,10 +105,16 @@  class transaction(object):
         self.entries = [] = {}
         self.journal = journalname
         self.undoname = undoname
         self._queue = []
+        # A callback to validate transaction content before closing it.
+        # should raise exception is anything is wrong.
+        # target user is repository hooks.
+        if validator is None:
+            validator = lambda tr: None
+        self.validator = validator
         # a dict of arguments to be passed to hooks
         self.hookargs = {}
         self.file =, "w")
         # a list of ('location', 'path', 'backuppath', cache) entries.
@@ -376,10 +382,11 @@  class transaction(object):
     def close(self):
         '''commit the transaction'''
         if self.count == 1:
+            self.validator(self)  # will raise exception if needed
             categories = sorted(self._finalizecallback)
             for cat in categories: