监听github,自动编译octopress博客

Page content

为了方便在任何地方修改blog,我将blog源码存放于github上,挂在一个web hook,这样一旦blog有更新, VPS上就会执行脚本重新生成新的blog,看起来还是非常方便的。

1. 添加github钩子

首先需要将octopress的代码(我比较懒,全部的代码)放到github上。 在github的项目设置的Service Hooks中添加一个WebHook URLs的钩子, 例如:

http://imxylz.com/blog-update

下载github代码,例如存放于/data目录下:

git clone git@github.com:adyliu/imxylz.com.git /data/imxylz.com

2. 设置nginx

nginx增加一个location配置

location /blog-update {
    proxy_pass http://127.0.0.1:1111;
}

3. 增加web钩子

这里使用python 开启一个web服务,拦截任何HTTP请求都执行我们的编译脚本

[root@www imxylz.com]# cat hook.py
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
# start a python service and watch the nginx request dog

from http.server import HTTPServer,CGIHTTPRequestHandler
from threading import Thread,RLock
import subprocess
import logging
import sys
import os.path


_PWD=os.path.abspath(os.path.dirname(__file__))
def execute_cmd(args,cwd=None,timeout=30):
    if isinstance(args,str): args = [args]
    try:
        with subprocess.Popen(args,stdout=subprocess.PIPE,cwd=cwd) as proc:
            try:
                output,unused_err = proc.communicate(timeout=timeout)
            except:
                proc.kill()
                raise
            retcode = proc.poll()
            if retcode:
                raise subprocess.CalledProcessError(retcode, proc.args, output=output)
            return output.decode('utf-8','ignore') if output else ''
    except Exception as ex:
        logging.error('EXECUTE_CMD_ERROR: %s',' '.join(str(x) for x in args))
        raise ex

class HttpHandler(CGIHTTPRequestHandler):
    _lock = RLock()
    _counter = 0
    _building = False

    def build(self):
        with HttpHandler._lock:
            if HttpHandler._counter == 0 or HttpHandler._building:
                return
        HttpHandler._counter = 0
        HttpHandler._building = True
        logging.info("BUILDING NOW...")
        try:
            resp = execute_cmd(os.path.join(_PWD,'build.sh'),cwd=_PWD,timeout=600)
            logging.info(resp)
        finally:
            HttpHandler._building = False
            self.build()

    def do_GET(self):
        self.do_POST()
    def do_POST(self):
        self.send_response(200,'OK')
        self.end_headers()
        self.wfile.write(b'OK')
        self.wfile.flush()
        with HttpHandler._lock:
            HttpHandler._counter += 1
        Thread(target=self.build).start()

if __name__ == '__main__':
    logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s',level=logging.INFO)

    port = int(sys.argv[1]) if len(sys.argv) > 1 else 1111
    logging.info('starting the server at 127.0.0.1:%s',port)
    httpd = HTTPServer(('127.0.0.1',port),HttpHandler)
    httpd.serve_forever()

4. 生成blog脚本

为了方便扩展,这里使用一个build.sh脚本来编译octopress。

#!/bin/bash

echo "build at `date`"
git pull
rake generate

5. 启动hook

最后启动hook来监听github变更:

nohup python3 hook.py >> /tmp/hook.log 2>&1 &

需要注意的是,build.sh/hook.py 需要放在octopress的根目录下面,另外rake环境也需要准备好,如果不能可以在build.sh里面设置环境变量。

如果要测试可以发送http请求即可。

curl http://127.0.0.1:1111/

此时我只需要将本地blog源码修改后push到github上,VPS机器就会执行脚本重新发布blog了。