changeset 1736:50de0887bbcd

add preoutgoing and outgoing hooks. preoutgoing lets prevent pull over http or ssh. outgoing lets notify after pull.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Fri, 17 Feb 2006 08:26:21 -0800
parents 791405fe9991
children 2c9872a4f3fd f95654385065
files doc/hgrc.5.txt mercurial/commands.py mercurial/hgweb.py mercurial/httprepo.py mercurial/localrepo.py mercurial/sshrepo.py tests/test-hook tests/test-hook.out
diffstat 8 files changed, 60 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/doc/hgrc.5.txt	Thu Feb 16 14:34:59 2006 -0800
+++ b/doc/hgrc.5.txt	Fri Feb 17 08:26:21 2006 -0800
@@ -160,6 +160,10 @@
     Run after a changeset has been pulled, pushed, or unbundled into
     the local repository.  The ID of the newly arrived changeset is in
     $HG_NODE.
+  outgoing;;
+    Run after sending changes from local repository to another.  ID of
+    first changeset sent is in $HG_NODE.  Source of operation is in
+    $HG_SOURCE; see "preoutgoing" hook for description.
   prechangegroup;;
     Run before a changegroup is added via push, pull or unbundle.
     Exit status 0 allows the changegroup to proceed.  Non-zero status
@@ -168,6 +172,15 @@
     Run before starting a local commit.  Exit status 0 allows the
     commit to proceed.  Non-zero status will cause the commit to fail.
     Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
+  preoutgoing;;
+    Run before computing changes to send from the local repository to
+    another.  Non-zero status will cause failure.  This lets you
+    prevent pull over http or ssh.  Also prevents against local pull,
+    push (outbound) or bundle commands, but not effective, since you
+    can just copy files instead then.  Source of operation is in
+    $HG_SOURCE.  If "serve", operation is happening on behalf of
+    remote ssh or http repository.  If "push", "pull" or "bundle",
+    operation is happening on behalf of repository on same system.
   pretag;;
     Run before creating a tag.  Exit status 0 allows the tag to be
     created.  Non-zero status will cause the tag to fail.  ID of
--- a/mercurial/commands.py	Thu Feb 16 14:34:59 2006 -0800
+++ b/mercurial/commands.py	Fri Feb 17 08:26:21 2006 -0800
@@ -622,7 +622,7 @@
     dest = ui.expandpath(dest, repo.root)
     other = hg.repository(ui, dest)
     o = repo.findoutgoing(other)
-    cg = repo.changegroup(o)
+    cg = repo.changegroup(o, 'bundle')
 
     try:
         f.write("HG10")
@@ -1999,7 +1999,7 @@
                 arg, roots = getarg()
                 nodes = map(bin, roots.split(" "))
 
-                cg = repo.changegroup(nodes)
+                cg = repo.changegroup(nodes, 'serve')
                 while 1:
                     d = cg.read(4096)
                     if not d:
--- a/mercurial/hgweb.py	Thu Feb 16 14:34:59 2006 -0800
+++ b/mercurial/hgweb.py	Fri Feb 17 08:26:21 2006 -0800
@@ -962,7 +962,7 @@
                 nodes = map(bin, req.form['roots'][0].split(" "))
 
             z = zlib.compressobj()
-            f = self.repo.changegroup(nodes)
+            f = self.repo.changegroup(nodes, 'serve')
             while 1:
                 chunk = f.read(4096)
                 if not chunk:
--- a/mercurial/httprepo.py	Thu Feb 16 14:34:59 2006 -0800
+++ b/mercurial/httprepo.py	Fri Feb 17 08:26:21 2006 -0800
@@ -119,7 +119,7 @@
             self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
             raise
 
-    def changegroup(self, nodes):
+    def changegroup(self, nodes, kind):
         n = " ".join(map(hex, nodes))
         f = self.do_cmd("changegroup", roots=n)
         bytes = 0
--- a/mercurial/localrepo.py	Thu Feb 16 14:34:59 2006 -0800
+++ b/mercurial/localrepo.py	Fri Feb 17 08:26:21 2006 -0800
@@ -957,9 +957,9 @@
             return 1
 
         if heads is None:
-            cg = remote.changegroup(fetch)
+            cg = remote.changegroup(fetch, 'pull')
         else:
-            cg = remote.changegroupsubset(fetch, heads)
+            cg = remote.changegroupsubset(fetch, heads, 'pull')
         return self.addchangegroup(cg)
 
     def push(self, remote, force=False):
@@ -984,10 +984,10 @@
                                  " use push -f to force)\n"))
                 return 1
 
-        cg = self.changegroup(update)
+        cg = self.changegroup(update, 'push')
         return remote.addchangegroup(cg)
 
-    def changegroupsubset(self, bases, heads):
+    def changegroupsubset(self, bases, heads, source):
         """This function generates a changegroup consisting of all the nodes
         that are descendents of any of the bases, and ancestors of any of
         the heads.
@@ -999,6 +999,8 @@
         Another wrinkle is doing the reverse, figuring out which changeset in
         the changegroup a particular filenode or manifestnode belongs to."""
 
+        self.hook('preoutgoing', throw=True, source=source)
+
         # Set up some initial variables
         # Make it easy to refer to self.changelog
         cl = self.changelog
@@ -1251,14 +1253,19 @@
             # Signal that no more groups are left.
             yield struct.pack(">l", 0)
 
+            self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source)
+
         return util.chunkbuffer(gengroup())
 
-    def changegroup(self, basenodes):
+    def changegroup(self, basenodes, source):
         """Generate a changegroup of all nodes that we have that a recipient
         doesn't.
 
         This is much easier than the previous function as we can assume that
         the recipient has any changenode we aren't sending them."""
+
+        self.hook('preoutgoing', throw=True, source=source)
+
         cl = self.changelog
         nodes = cl.nodesbetween(basenodes, None)[0]
         revset = dict.fromkeys([cl.rev(n) for n in nodes])
@@ -1310,6 +1317,7 @@
                         yield chnk
 
             yield struct.pack(">l", 0)
+            self.hook('outgoing', node=hex(nodes[0]), source=source)
 
         return util.chunkbuffer(gengroup())
 
--- a/mercurial/sshrepo.py	Thu Feb 16 14:34:59 2006 -0800
+++ b/mercurial/sshrepo.py	Fri Feb 17 08:26:21 2006 -0800
@@ -110,7 +110,7 @@
         except:
             raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "..."))
 
-    def changegroup(self, nodes):
+    def changegroup(self, nodes, kind):
         n = " ".join(map(hex, nodes))
         f = self.do_cmd("changegroup", roots=n)
         return self.pipei
--- a/tests/test-hook	Thu Feb 16 14:34:59 2006 -0800
+++ b/tests/test-hook	Fri Feb 17 08:26:21 2006 -0800
@@ -74,3 +74,17 @@
 echo 'pretxnchangegroup.forbid = echo pretxnchangegroup.forbid hook: tip=`hg -q tip`; exit 1' >> .hg/hgrc
 hg pull ../a
 hg -q tip
+
+# outgoing hooks can see env vars
+rm .hg/hgrc
+echo '[hooks]' > ../a/.hg/hgrc
+echo 'preoutgoing = echo preoutgoing hook: s=$HG_SOURCE' >> ../a/.hg/hgrc
+echo 'outgoing = echo outgoing hook: n=$HG_NODE s=$HG_SOURCE' >> ../a/.hg/hgrc
+hg pull ../a
+hg undo
+
+# preoutgoing hook can prevent outgoing changes
+echo 'preoutgoing.forbid = echo preoutgoing.forbid hook; exit 1' >> ../a/.hg/hgrc
+hg pull ../a
+
+exit 0
--- a/tests/test-hook.out	Thu Feb 16 14:34:59 2006 -0800
+++ b/tests/test-hook.out	Fri Feb 17 08:26:21 2006 -0800
@@ -71,3 +71,18 @@
 transaction abort!
 rollback completed
 3:07f3376c1e65
+preoutgoing hook: s=pull
+outgoing hook: n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 s=pull
+pulling from ../a
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+(run 'hg update' to get a working copy)
+rolling back last transaction
+preoutgoing hook: s=pull
+preoutgoing.forbid hook
+pulling from ../a
+searching for changes
+abort: preoutgoing.forbid hook exited with status 1