add preoutgoing and outgoing hooks.
authorVadim Gelfer <vadim.gelfer@gmail.com>
Fri, 17 Feb 2006 08:26:21 -0800
changeset 1736 50de0887bbcd
parent 1735 791405fe9991
child 1737 2c9872a4f3fd
child 1740 f95654385065
add preoutgoing and outgoing hooks. preoutgoing lets prevent pull over http or ssh. outgoing lets notify after pull.
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
--- 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