瀏覽代碼

post-receive hook (#743)

Add support for running post-receive hook.
battlmonstr 5 年之前
父節點
當前提交
e2735e84d4
共有 3 個文件被更改,包括 56 次插入0 次删除
  1. 40 0
      dulwich/hooks.py
  2. 2 0
      dulwich/repo.py
  3. 14 0
      dulwich/server.py

+ 40 - 0
dulwich/hooks.py

@@ -160,3 +160,43 @@ class CommitMsgShellHook(ShellHook):
 
         ShellHook.__init__(self, 'commit-msg', filepath, 1,
                            prepare_msg, clean_msg, controldir)
+
+
+class PostReceiveShellHook(ShellHook):
+    """post-receive shell hook"""
+
+    def __init__(self, controldir):
+        self.controldir = controldir
+        filepath = os.path.join(controldir, 'hooks', 'post-receive')
+        ShellHook.__init__(self, 'post-receive', filepath, 0)
+
+    def execute(self, client_refs):
+        # do nothing if the script doesn't exist
+        if not os.path.exists(self.filepath):
+            return None
+
+        try:
+            env = os.environ.copy()
+            env['GIT_DIR'] = self.controldir
+
+            p = subprocess.Popen(
+                self.filepath,
+                stdin=subprocess.PIPE,
+                stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE,
+                env=env
+            )
+
+            # client_refs is a list of (oldsha, newsha, ref)
+            in_data = '\n'.join([' '.join(ref) for ref in client_refs])
+
+            out_data, err_data = p.communicate(in_data)
+
+            if (p.returncode != 0) or err_data:
+                err_fmt = "post-receive exit code: %d\n" \
+                    + "stdout:\n%s\nstderr:\n%s"
+                err_msg = err_fmt % (p.returncode, out_data, err_data)
+                raise HookError(err_msg)
+            return out_data
+        except OSError as err:
+            raise HookError(repr(err))

+ 2 - 0
dulwich/repo.py

@@ -70,6 +70,7 @@ from dulwich.hooks import (
     PreCommitShellHook,
     PostCommitShellHook,
     CommitMsgShellHook,
+    PostReceiveShellHook,
     )
 
 from dulwich.line_ending import BlobNormalizer
@@ -955,6 +956,7 @@ class Repo(BaseRepo):
         self.hooks['pre-commit'] = PreCommitShellHook(self.controldir())
         self.hooks['commit-msg'] = CommitMsgShellHook(self.controldir())
         self.hooks['post-commit'] = PostCommitShellHook(self.controldir())
+        self.hooks['post-receive'] = PostReceiveShellHook(self.controldir())
 
     def _write_reflog(self, ref, old_sha, new_sha, committer, timestamp,
                       timezone, message):

+ 14 - 0
dulwich/server.py

@@ -59,6 +59,7 @@ from dulwich.errors import (
     ApplyDeltaError,
     ChecksumMismatch,
     GitProtocolError,
+    HookError,
     NotGitRepository,
     UnexpectedCommandError,
     ObjectFormatException,
@@ -981,6 +982,17 @@ class ReceivePackHandler(PackHandler):
         write(None)
         flush()
 
+    def _on_post_receive(self, client_refs):
+        hook = self.repo.hooks.get('post-receive', None)
+        if not hook:
+            return
+        try:
+            output = hook.execute(client_refs)
+            if output:
+                self.proto.write_sideband(SIDE_BAND_CHANNEL_PROGRESS, output)
+        except HookError as err:
+            self.proto.write_sideband(SIDE_BAND_CHANNEL_FATAL, repr(err))
+
     def handle(self):
         if self.advertise_refs or not self.http_req:
             refs = sorted(self.repo.get_refs().items())
@@ -1018,6 +1030,8 @@ class ReceivePackHandler(PackHandler):
         # backend can now deal with this refs and read a pack using self.read
         status = self._apply_pack(client_refs)
 
+        self._on_post_receive(client_refs)
+
         # when we have read all the pack from the client, send a status report
         # if the client asked for it
         if self.has_capability(CAPABILITY_REPORT_STATUS):