IMXYLZ

监听github,自动编译octopress博客

| Comments

为了方便在任何地方修改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了。

清理Eclipse升级后的旧插件

| Comments

Eclipse 升级后一些插件有很多版本,尽管不影响使用,但对于我这种强迫症的人来说,就希望清理它们。

以前手工一个一个删除,太费劲,而且容易导致误删除。 Google后发现stackoverflow 上有一个提问, 下载下来后执行下生成一个要删除的文件列表。

一番执行后居然误删除了一个文件:

org.eclipse.swt.cocoa.macosx.x86_64_3.102.1.v20130827-2048.jar

结果Eclipse就无法启动了。

Google 下可以去这里下载一份,替换即可。 我第一次是从http://dev.caleydo.org下载 的pack200格式,用下面的命令解压缩即可得到原始jar文件:

unpack200 org.eclipse.swt.cocoa.macosx.x86_64_3.102.1.v20130827-2048.jar.pack.gz org.eclipse.swt.cocoa.macosx.x86_64_3.102.1.v20130827-2048.jar

➜ ~/Downloads $ ll org.eclipse.swt.cocoa.macosx.x86_64_3.102.1.v20130827-2048.jar*
-rw-r--r--  1 adyliu  staff   2.1M 11  8 14:00 org.eclipse.swt.cocoa.macosx.x86_64_3.102.1.v20130827-2048.jar
-rw-r--r--@ 1 adyliu  staff   836K 11  4 11:04 org.eclipse.swt.cocoa.macosx.x86_64_3.102.1.v20130827-2048.jar.pack.gz

对比下tgz,pack200对jar的压缩效果真是明显:

➜ ~/Downloads $ ll org.eclipse.swt.cocoa.macosx.x86_64_3.102.1.v20130827-2048.jar*
-rw-r--r--  1 adyliu  staff   2.1M 11  8 14:00 org.eclipse.swt.cocoa.macosx.x86_64_3.102.1.v20130827-2048.jar
-rw-r--r--@ 1 adyliu  staff   836K 11  4 11:04 org.eclipse.swt.cocoa.macosx.x86_64_3.102.1.v20130827-2048.jar.pack.gz
-rw-r--r--  1 adyliu  staff   2.0M 11  8 14:01 org.eclipse.swt.cocoa.macosx.x86_64_3.102.1.v20130827-2048.jar.tgz

CentOS 6 下安装Python 3

| Comments

CentOS 6.x 默认带的Python 还是2.6版本,我们大量的程序都在python 3.x下运行, 因此需要手动安装python 3。

由于没有编译好的rpm包安装,于是手动编译安装即可。好在python编译非常简单,而且还算是比较快。 (相对于macport。的编译来说已经好多了)

安装依赖

在配置安装之前,需要安装一些依赖库,不然会导致一些功能不可用。

#yum install -y gcc make openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel

配置安装

下载最新的安装包(截止2013/11/05),还是3.3.2版本。

#wget http://python.org/ftp/python/3.3.2/Python-3.3.2.tgz
#tar xzf Python-3.3.2.tgz
#cd Python-3.3.2
#./configure --prefix=/opt/apps/python3
#make
#make install

如果没有指定prefix,将默认安装在/usr/local下,因此PATH中可以找到。我们要安装一个可以复制安装的版本,所以安装在指定目录下。

设置环境

可以将/opt/apps/python3/bin加入系统环境变量,

#echo 'export PATH=$PATH:/opt/apps/python3/bin' >> ~/.bash_profile

而我们简单的建立软链接比较方便

#ln -s /opt/apps/python3/bin/python3 /usr/bin

确认安装成功

# python3 -V
Python 3.3.2

安装pip

pip用于安装依赖软件比较方便,因此推荐安装上.

#wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - |python3
#wget https://raw.github.com/pypa/pip/master/contrib/get-pip.py -O - |python3
#ln -s /opt/apps/python3.3/bin/pip-3.3 /usr/bin/

安装需要的第三方库

例如mysql-connector和requests

#pip-3.3 install mysql-connector-python
#pip-3.3 install requests

如果安装pip时发生如下错误:

ImportError: No module named bz2

那么说明安装的python 3 缺少依赖库bzip2-devel,需要先安装依赖库然后再编译安装。

查看已安装Python的编译参数可参考: stackoverflow

Bash命令路径的缓存

| Comments

升级到OS X 10.9后,系统默认的python已经升级到2.7.5了,所以以前通过ports安装的2.7.3版本就没有必要了。 于是就使用port卸载了。

sudo port uninstall --follow-dependents python27

完整的问题描述在这

最后通过Google找到答案,原来Bash会对命令的路径解析进行缓存。

通过hash -l命令可以查看当前所有缓存的命令路径:

➜ ~ $ hash -l
builtin hash -p /Users/adyliu/bin/hosts hosts
builtin hash -p /usr/bin/which which
builtin hash -p /usr/bin/host host
builtin hash -p /usr/bin/python2.6 python2.6
builtin hash -p /usr/bin/python2.7 python2.7
builtin hash -p /usr/bin/locate locate
builtin hash -p /usr/bin/python2.5 python2.5
builtin hash -p /usr/bin/du du
builtin hash -p /bin/cat cat
builtin hash -p /usr/bin/vim vim
builtin hash -p /usr/bin/sudo sudo
builtin hash -p /usr/bin/java java
builtin hash -p /usr/bin/uname uname
builtin hash -p /opt/local/bin/python2 python2
builtin hash -p /usr/local/bin/python3 python3
builtin hash -p /usr/bin/man man
builtin hash -p /usr/bin/less less
builtin hash -p /opt/local/bin/otool otool
builtin hash -p /bin/ls ls
builtin hash -p /usr/bin/python python

可通过如下命令之一清除缓存:

hash -r
hash -d python2.7

Bash 为了提高命令的解析速度,将解析过的命令的全路径保存在hash表中,因此下次执行的时候就无需进行再次解析。

hash 有如下几个参数:

  • -d [name]… 删除某个命令的路径缓存
  • -r 删除所有命令的路径缓存
  • -t [name] 列出某个命令的缓存路径(如果有的话)
  • -l 列出全部的路径缓存

可使用 help hash 来查看帮助,不过文档没有格式化,比较难看。

MAC下批量转换PNG和JPEG

| Comments

OS X下有一个sips的程序可以用来处理图片。 sips的名称功能非常强大,参考帮助文档

这里我们只用到其中的一个功能,转换图片格式。

命令参考:

sips -s format jpeg --out b.jpg a.png

写一个png批量转换jpg的脚本:

cat  ~/bin/png2jpg
#!/bin/bash
# convert png files to jpeg files
# usage: png2jpg <file>...

for f in "$@"
do
    sips -s format jpeg --out "${f%.*}.jpg" "$f"
done

同样写一个jpg批量转换png的脚本:

cat ~/bin/jpg2png
#!/bin/bash
# convert jpeg files to png files
# usage: jpg2png <file>...

for f in "$@"
do
    sips -s format png --out "${f%.*}.png" "$f"
done

使用例子:

➜ ~/Downloads $ png2jpg QQ20131008-*.png
/Users/adyliu/Downloads/QQ20131008-2.png
  /Users/adyliu/Downloads/QQ20131008-2.jpg
/Users/adyliu/Downloads/QQ20131008-3.png
  /Users/adyliu/Downloads/QQ20131008-3.jpg
/Users/adyliu/Downloads/QQ20131008-4.png
  /Users/adyliu/Downloads/QQ20131008-4.jpg
➜ ~/Downloads $ ll QQ*
-rw-r--r--  1 adyliu  staff    67K 10  8 15:43 QQ20131008-2.jpg
-rw-r--r--@ 1 adyliu  staff    88K 10  8 15:31 QQ20131008-2.png
-rw-r--r--  1 adyliu  staff    23K 10  8 15:43 QQ20131008-3.jpg
-rw-r--r--@ 1 adyliu  staff    34K 10  8 15:31 QQ20131008-3.png
-rw-r--r--  1 adyliu  staff    47K 10  8 15:43 QQ20131008-4.jpg
-rw-r--r--@ 1 adyliu  staff    44K 10  8 15:31 QQ20131008-4.png

参考资料:

  1. sips doc
  2. Resizing images using the command line
  3. Shell Parameter Expansion
  4. Extract filename and extension in bash

跑步累计50公里

| Comments

50km

早上跑步后终于累计达到50公里了,Nike Running 也换了颜色。

老实说前段时间膝盖和脚踝受伤一直未好,休息了大半个月。最近好多了,早上起来偶尔跑步。 小区没有比较好的跑道,容易受伤,一般早上只能跑步一公里多点。 如果得闲还是应该去森林公园才是。

话说,好久没有阅读了,今年的阅读目标难以完成了。 离年终只有99天了,特地买了本《拖延心理学》此书, 是应该坚持下来。

Octopress加速Google字体渲染

| Comments

默认Octopress使用Google API的WEB字体渲染CSS。利用Google的CDN,在国外网络访问还是非常快的。

<!--Fonts from Google's Web font directory at http://google.com/webfonts -->
<link href='http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic' rel='stylesheet' type='text/css'>

但是在天朝,非常非常慢,尤其是使用了HTTPS来访问以后,几乎无法忍受。

于是想将CSS/FONTS下载到本地来渲染,这样加速网络访问。

首先将’http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic‘下载到本地来,文件内容为:

@font-face {
  font-family: 'PT Serif';
  font-style: normal;
  font-weight: 400;
  src: local('PT Serif'), local('PTSerif-Regular'), url(http://themes.googleusercontent.com/static/fonts/ptserif/v5/sDRi4fY9bOiJUbgq53yZCXYhjbSpvc47ee6xR_80Hnw.woff) format('woff');
}
@font-face {
  font-family: 'PT Serif';
  font-style: normal;
  font-weight: 700;
  src: local('PT Serif Bold'), local('PTSerif-Bold'), url(http://themes.googleusercontent.com/static/fonts/ptserif/v5/QABk9IxT-LFTJ_dQzv7xpLrIa-7acMAeDBVuclsi6Gc.woff) format('woff');
}
@font-face {
  font-family: 'PT Serif';
  font-style: italic;
  font-weight: 400;
  src: local('PT Serif Italic'), local('PTSerif-Italic'), url(http://themes.googleusercontent.com/static/fonts/ptserif/v5/03aPdn7fFF3H6ngCgAlQzL3hpw3pgy2gAi-Ip7WPMi0.woff) format('woff');
}
@font-face {
  font-family: 'PT Serif';
  font-style: italic;
  font-weight: 700;
  src: local('PT Serif Bold Italic'), local('PTSerif-BoldItalic'), url(http://themes.googleusercontent.com/static/fonts/ptserif/v5/Foydq9xJp--nfYIx2TBz9XbFhgvWbfSbdVg11QabG8w.woff) format('woff');
}

然后将所有字体文件下载到本地,并将css中的链接地址都改为本地地址。

如果更快点,可以将两个css文件合并成一个google-fonts.css。

➜ ~/codes/imxylz.com (master) $ cat source/stylesheets/google-fonts.css
@font-face {
  font-family: 'PT Serif';
  font-style: normal;
  font-weight: 400;
  src: local('PT Serif'), local('PTSerif-Regular'), url(/stylesheets/EgBlzoNBIHxNPCMwXaAhYPesZW2xOQ-xsNqO47m55DA.ttf) format('truetype');
}
@font-face {
  font-family: 'PT Serif';
  font-style: normal;
  font-weight: 700;
  src: local('PT Serif Bold'), local('PTSerif-Bold'), url(/stylesheets/QABk9IxT-LFTJ_dQzv7xpJ0EAVxt0G0biEntp43Qt6E.ttf) format('truetype');
}
@font-face {
  font-family: 'PT Serif';
  font-style: italic;
  font-weight: 400;
  src: local('PT Serif Italic'), local('PTSerif-Italic'), url(/stylesheets/03aPdn7fFF3H6ngCgAlQzC3USBnSvpkopQaUR-2r7iU.ttf) format('truetype');
}
@font-face {
  font-family: 'PT Serif';
  font-style: italic;
  font-weight: 700;
  src: local('PT Serif Bold Italic'), local('PTSerif-BoldItalic'), url(/stylesheets/Foydq9xJp--nfYIx2TBz9fEr6Hm6RMS0v1dtXsGir4g.ttf) format('truetype');
}
@font-face {
  font-family: 'PT Sans';
  font-style: normal;
  font-weight: 400;
  src: local('PT Sans'), local('PTSans-Regular'), url(/stylesheets/FUDHvzEKSJww3kCxuiAo2A.ttf) format('truetype');
}
@font-face {
  font-family: 'PT Sans';
  font-style: normal;
  font-weight: 700;
  src: local('PT Sans Bold'), local('PTSans-Bold'), url(/stylesheets/0XxGQsSc1g4rdRdjJKZrNC3USBnSvpkopQaUR-2r7iU.ttf) format('truetype');
}
@font-face {
  font-family: 'PT Sans';
  font-style: italic;
  font-weight: 400;
  src: local('PT Sans Italic'), local('PTSans-Italic'), url(/stylesheets/PIPMHY90P7jtyjpXuZ2cLKCWcynf_cDxXwCLxiixG1c.ttf) format('truetype');
}
@font-face {
  font-family: 'PT Sans';
  font-style: italic;
  font-weight: 700;
  src: local('PT Sans Bold Italic'), local('PTSans-BoldItalic'), url(/stylesheets/lILlYDvubYemzYzN7GbLkInF5uFdDttMLvmWuJdhhgs.ttf) format('truetype');
}

最后修改 /source/_include/custom/head.html 文件:

<link href="/stylesheets/google-fonts.css" rel="stylesheet" type="text/css">

全部文件列表为:

➜ ~/codes/imxylz.com (master) $ ls -lh source/stylesheets/
total 1632
-rw-r--r--  1 adyliu  staff    90K  5  2 02:24 03aPdn7fFF3H6ngCgAlQzC3USBnSvpkopQaUR-2r7iU.ttf
-rw-r--r--  1 adyliu  staff   115K  5  2 02:24 0XxGQsSc1g4rdRdjJKZrNC3USBnSvpkopQaUR-2r7iU.ttf
-rw-r--r--  1 adyliu  staff    85K  5  2 02:24 EgBlzoNBIHxNPCMwXaAhYPesZW2xOQ-xsNqO47m55DA.ttf
-rw-r--r--  1 adyliu  staff   110K  5  2 02:24 FUDHvzEKSJww3kCxuiAo2A.ttf
-rw-r--r--  1 adyliu  staff    80K  5  2 02:24 Foydq9xJp--nfYIx2TBz9fEr6Hm6RMS0v1dtXsGir4g.ttf
-rw-r--r--  1 adyliu  staff   109K  5  2 02:24 PIPMHY90P7jtyjpXuZ2cLKCWcynf_cDxXwCLxiixG1c.ttf
-rw-r--r--  1 adyliu  staff    80K  5  2 02:24 QABk9IxT-LFTJ_dQzv7xpJ0EAVxt0G0biEntp43Qt6E.ttf
-rw-r--r--  1 adyliu  staff   1.7K  9 22 20:52 google-fonts.css
-rw-r--r--  1 adyliu  staff    89K  5  2 02:24 lILlYDvubYemzYzN7GbLkInF5uFdDttMLvmWuJdhhgs.ttf
-rw-r--r--  1 adyliu  staff    39K  9 22 20:54 screen.css

再次访问网站,速度快多了,HTTPS也更快了。当然也失去了Google CDN的加速功能。

申请SSL证书及Nginx支持HTTPS

| Comments

申请SSL证书

每年2.5$ 的SSL证书申请地址在这里: https://billing.centriohost.com/cart.php?a=add&pid=21

打开后看到原价是10$/年,域名使用泛域名: *.imxylz.com,服务器IP地址需要提供公网IP地址。邮件的前缀可以选择一个,后缀是域名地址。 当然需要一个2048位的CSR。

生成一个CSR私钥,可以使用下面的名称:

#openssl genrsa -out imxylz.com.pem 2048
#openssl req -new -key imxylz.com.pem -out imxylz.com.csr

需要注意的是生成csr最好不输入密码,否则某些web服务器(例如apache)启动时需要输入密码。 另外CN (Common Name is a Necessary Item) 应该是 *.imxylz.com,否则会被拒绝。 (我在这个地方折腾好久,最后发ticket更换csr才解决)。

然后在下一页付款是输入优惠码 LET2SSL ,即可优惠7.5$,这样就只剩下2.5$/年了。 以后每年续费也按照这个价格进行。

付款完成后系统会发送邮件给第一步选择的邮箱地址: 前缀@imxylz.com,例如我的是: admin@imxylz.com

特别注意的是:由于邮件会发送给admin@imxylz.com,因此需要提前准备好邮件服务器,例如我当时就安装了postfix又来接收邮件。

由于pop3没有安装成功,因此我将收到的邮件 /root/Maildir/new/xxxxxx 下载回来,改成.eml后缀文件用OS X的Mail打开的。 邮件中有一个链接地址,需要确认信息是否正确,确认即可。(如果不确认及意味着操作失败,不能进行以后的操作了)。

比较悲剧的是我当时将邮件服务器搞坏了,没有收到邮件,最后只好发送ticket请求重发。 好在工作人员非常厚道,将证书发送给admin@imxylz.com以及我的gmail邮箱。 正常应该不发送给非域名邮箱的。

再次表扬下centriohost网站的工作人员,对ticket的处理比较及时。不爽的地方在于注册的时候会将密码明文发送到注册邮箱中。

Nginx 安装证书

邮件中有两个证书,一个是域名证书,一个是根证书。 将两个证书合并成一个文本文件(包括注释) imxylz.com.crt。 (注意域名证书在上,根证书在下,否则nginx启动会报错误。)

现在我们需要两个文件: imxylz.com.pem以及imxylz.com.crt。

  1. 编译Nginx

如果nginx没有支持SSL,则需要重新编译。可通过 nginx -V 来检查是否支持SSL。

#./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
#make
#make install
  1. 配置证书

将证书拷贝到/usr/local/nginx/conf中,然后配置(/usr/local/nginx/conf/nginx.conf)如下:

server {
    listen 443;
    server_name imxylz.com;
    index index.html;
    ssl on;
    ssl_certificate /usr/local/nginx/conf/imxylz.com.crt;
    ssl_certificate_key /usr/local/nginx/conf/imxylz.com.pem;
    location / {
        root /data/imxylz.com/public;
    }
}

测试下nginx并运行。

#/usr/local/nginx/sbin/nginx -t
#/usr/local/nginx/sbin/nginx

现在就可以通过 https://imxylz.com 访问HTTPS服务了。 当然如果网站有非https的资源,就需要改造地址,否则Windows下浏览器会弹出警告。 例如:

dsq.src = '//' + disqus_shortname + '.disqus.com/' + disqus_script;
<link href="//fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">

最终的效果图如下: ssl on imxylz.com

如果有问题,可以检查nginx的error_log。

跑步持续一周

| Comments

毫无疑问,跑步能够持续一周对于我来说已经是很艰难的事情了。 好在我坚持了下来。

尽管有一段时间在快走,但5公里能够坚持下来已经是很大的突破了。 周末连续两天坚持5公里,实在是不易。

持续跑步一周

其实咬咬牙5公里应该是能够坚持下来的,只是没有动力去挖掘身体的潜力罢了。 最近几天每天都感觉到腿部比较乏力,很显然是透支体力导致的,只是还没有习惯这种节奏。 长时间的不运动,一旦运动起来,甚至透支些体力显然难以吃消。 上周除了周一临时有事没有跑步外,其它每天都有跑步,一共运动了19.6公里。 这对于我来说已经是莫大的进步了。

除了运动,也许还需要在饮食上稍微注意些。

继续坚持吧。

5公里

| Comments

奥林匹克森林公园

奥林匹克森林公园的天气看起来不错,跑道上运动的人也挺多的。

在跑步之前特地在优酷上看了下跑步的正确姿势和热身运动。昨晚热身运动后慢跑一公里多点, 然后开始做第二遍热身运动。稍微活动了下,继续跑步。 最终在边跑边走的情况下,完成了5公里的运动。 当然中间有两段走的距离没有统计,所以运动轨迹看起来是断的。

好在这次坚持到最后不是特别疲惫,出门后就直接坐车回家了。 这应该是最近十年的跑步最长的一次距离。可见是多么的缺乏运动。

5公里

如果每周都能够坚持下去,也许年底我就能跑完全程了。当然,按照以往的情况,一旦定好了目标, 这事情估计就黄了。

接下来应该考虑今年的阅读目标了。

回顶部