Commits

Anonymous committed 85fd998

Rename extension to "hgban"

This reflects the new nature of the extension, which is no longer limited to
just banning changesets. Using revision sets it is now possible to ban any
revision that matches all sorts of conditions.

For example it could be possible to ban revisions that modify a given file, or
that habe been commited by a given user, etc.

Comments (0)

Files changed (2)

ban-changesets.py

-#!/usr/bin/env python
-
-'''ban-changesets is a Mercurial extension which sets up a pretxnchangegroup hook.
-Any changesets to be pushed / pulled / bundled into the repository will have their
-revision ids matched against a list of banned revision sets specified in 
-repo/.hgbannedchangesets.
-The banned revision sets can be from simple revision ids to complex revision
-set queries.
-
-If any new revision matches any of the revision sets in this file of banned
-revisions then the entire changegroup will be rejected.
-
-You can add comments to your .hgbannedchangesets file by beginning a line with
-a "#" character. You can put spaces in front of or after a revision set or
-comment and they will be ignored.
-
-Enable the ban-changesets just like any other Mercurial extension by adding the
-following to your hgrc
-
-[extensions]
-ban-changesets = /path/to/ban-changesets
-'''
-
-import os.path, re
-from mercurial import hg, revset
-
-
-def getSetOfBannedRevsets(repo):
-    try:
-        bannedRevsetsPath = repo.wjoin('.hgbannedchangesets')
-        f = open(bannedRevsetsPath, 'r')
-        banned = set()
-        commentPat = re.compile(r"#.*$")
-        nodePat = re.compile(r"\s*(^[0-9a-fA-F]+).*")
-        for line in f:
-            rset = line.strip()
-            m = re.match(commentPat, rset)
-            if not m:
-                if re.match(nodePat, rset):
-                    # Explicitly consider as node id references those
-                    # ban conditions matching the "node id pattern"
-                    rset = 'id(%s)' % rset
-                if rset:
-                    banned.add(rset)
-        f.close()
-
-        return banned
-    except:
-        return set()
-
-def getreposetfunc():
-    '''
-    Yield a context for each matching revision, after doing arg
-    replacement via revset.formatspec
-    '''
-    def rsetfunc(repo, expr, *args):
-        m = revset.match(None, expr)
-
-        for r in m(repo, range(len(repo))):
-            yield repo[r]
-
-    try:
-        # hg >= 2.0
-        return repo.set
-    except:
-        # hg <= 1.9
-        return rsetfunc
-
-def reposet(repo, expr, *args):
-    '''
-    Yield a context for each matching revision, after doing arg
-    replacement via revset.formatspec
-    '''
-
-    m = revset.match(None, expr)
-
-    for r in m(repo, range(len(repo))):
-        yield repo[r]
-
-def checkForBannedRevsets(ui, repo, **kwargs):
-    node = kwargs.get('node')
-    if node:
-        bannedRevsets = getSetOfBannedRevsets(repo)
-        if not bannedRevsets:
-            # Successful early exit if there are no banned changesets
-            return False
-
-        startRev = int(repo[node])
-        descendantRevs = list(repo.changelog.descendants(startRev))
-        descendantRevs.append(startRev)
-
-        rejectedChangesets = set()
-
-        for revsetexpr in bannedRevsets:
-            try:
-                rsetfunc = getreposetfunc()
-                for ctx in rsetfunc(repo, "%d: and (%s)" % (startRev, revsetexpr)):
-                    if ctx:
-                        rejectedChangesets.add(ctx.rev())
-            except:
-                # most likely, and no valid revisions were found
-                # if that is the case, we can simply check the next condition
-                continue
-
-        if len(rejectedChangesets) > 0:
-            repoName = os.path.basename(repo.root)
-            ui.warn('The ban-changeset extension rejected the %s operation on the repository \'%s\' due to the changeset(s):\n' % (kwargs.get('source'), repoName))
-            for changeset in rejectedChangesets:
-                ui.warn('    %s\n' % changeset)
-            if (len(rejectedChangesets) < len(descendantRevs)):
-                if len(rejectedChangesets) == 1:
-                    ui.warn('Rebase, transplant, or otherwise move any valid changesets in the source repository which are derived from this rejected changeset. Strip the banned changesets, and then redo the operation.\n')
-                else:
-                    ui.warn('Rebase, transplant, or otherwise move any valid changesets in the source repository which are derived from these rejected changesets. Strip the banned changesets, and then redo the operation.\n')
-            return True # We found a banned changeset, return True (exit code 1) which causes the changegroup addition to be aborted.
-    return False # No banned changesets were found. The changegroup addition can go ahead.
-
-def reposetup(ui, repo):
-    ui.setconfig("hooks", "pretxnchangegroup.ban-changesets", checkForBannedChangesets)
+#!/usr/bin/env python
+
+'''hgban is a Mercurial extension which can be used to abort any push, pull or
+bundle operation that matches a given criteria.
+
+The extension sets up a pretxnchangegroup hook, which is executed on every
+push, pull and bundle operation. The hook tries to match every new changesets
+in the changegroup that is being pushed, pulled or bundled into a repository
+against a list of "banned" revision sets.
+
+If any of the changesets in the changegroup matches any of the "banned"
+revision sets the entire changegroup is be rejected, and the push, pull or
+bundle operation is aborted.
+
+"banned" revisions are specified in a file called ".hgban" which must be
+placed at the root of the repository. Each line in that file corresponds to
+a banned revision set. A banned revision set can be specified as simple
+revision id or a a complex revision set query.
+
+You can add comments to your .hgban file by beginning a line with
+a "#" character. You can put spaces in front of or after a revision set or
+comment and they will be ignored.
+
+Enable the hgban extension just like any other Mercurial extension by adding
+the following to your hgrc:
+
+[extensions]
+hgban = /path/to/hgban.py
+'''
+
+import os.path, re
+from mercurial import hg, revset
+
+
+def getSetOfBannedRevsets(repo):
+    try:
+        bannedRevsetsPath = repo.wjoin('.hgban')
+        f = open(bannedRevsetsPath, 'r')
+        banned = set()
+        commentPat = re.compile(r"#.*$")
+        nodePat = re.compile(r"\s*(^[0-9a-fA-F]+).*")
+        for line in f:
+            rset = line.strip()
+            m = re.match(commentPat, rset)
+            if not m:
+                if re.match(nodePat, rset):
+                    # Explicitly consider as node id references those
+                    # ban conditions matching the "node id pattern"
+                    rset = 'id(%s)' % rset
+                if rset:
+                    banned.add(rset)
+        f.close()
+
+        return banned
+    except:
+        return set()
+
+def getreposetfunc():
+    '''
+    Yield a context for each matching revision, after doing arg
+    replacement via revset.formatspec
+    '''
+    def rsetfunc(repo, expr, *args):
+        m = revset.match(None, expr)
+
+        for r in m(repo, range(len(repo))):
+            yield repo[r]
+
+    try:
+        # hg >= 2.0
+        return repo.set
+    except:
+        # hg <= 1.9
+        return rsetfunc
+
+def reposet(repo, expr, *args):
+    '''
+    Yield a context for each matching revision, after doing arg
+    replacement via revset.formatspec
+    '''
+
+    m = revset.match(None, expr)
+
+    for r in m(repo, range(len(repo))):
+        yield repo[r]
+
+def checkForBannedRevsets(ui, repo, **kwargs):
+    node = kwargs.get('node')
+    if node:
+        bannedRevsets = getSetOfBannedRevsets(repo)
+        if not bannedRevsets:
+            # Successful early exit if there are no banned changesets
+            return False
+
+        startRev = int(repo[node])
+        descendantRevs = list(repo.changelog.descendants(startRev))
+        descendantRevs.append(startRev)
+
+        rejectedChangesets = set()
+
+        for revsetexpr in bannedRevsets:
+            try:
+                rsetfunc = getreposetfunc()
+                for ctx in rsetfunc(repo, "%d: and (%s)" % (startRev, revsetexpr)):
+                    if ctx:
+                        rejectedChangesets.add(ctx.rev())
+            except:
+                # most likely, and no valid revisions were found
+                # if that is the case, we can simply check the next condition
+                continue
+
+        if len(rejectedChangesets) > 0:
+            repoName = os.path.basename(repo.root)
+            ui.warn('The ban-changeset extension rejected the %s operation on the repository \'%s\' due to the changeset(s):\n' % (kwargs.get('source'), repoName))
+            for changeset in rejectedChangesets:
+                ui.warn('    %s\n' % changeset)
+            if (len(rejectedChangesets) < len(descendantRevs)):
+                if len(rejectedChangesets) == 1:
+                    ui.warn('Rebase, transplant, or otherwise move any valid changesets in the source repository which are derived from this rejected changeset. Strip the banned changesets, and then redo the operation.\n')
+                else:
+                    ui.warn('Rebase, transplant, or otherwise move any valid changesets in the source repository which are derived from these rejected changesets. Strip the banned changesets, and then redo the operation.\n')
+            return True # We found a banned changeset, return True (exit code 1) which causes the changegroup addition to be aborted.
+    return False # No banned changesets were found. The changegroup addition can go ahead.
+
+def reposetup(ui, repo):
+    ui.setconfig("hooks", "pretxnchangegroup.hgban", checkForBannedChangesets)