使用bash脚本更新和备份Ghost

Ghost 在版本更新这方面做得比较差,不仅没有自动更新,连新版本提醒都不及时,这方面比 Wordpress 差远了。我觉得他们不是不能做自动更新,只是不想做这个功能,促使用户去买他们的 Ghost Pro 托管服务。不过 Ghost 现在还在 0.11.* 版本,v1.0.0 还在 alpha 测试,算是情有可原吧。Github 上有一个 Ghost-CLI 的项目,CLI Tool for installing & updating Ghost,是 Ghost 官方搞的,但是不对 1.0.0 以下的版本提供支持,所以在 v1.0.0 正式发布之前,自己写一个脚本吧。

脚本要做下面这些事情:

  1. 检查最新版本和本地版本,确认是否需要更新
  2. 备份博客数据
  3. 下载最新版本,覆盖旧版本
  4. 更新依赖,重启服务
检查最新版本和本地版本

Ghost 的本地版本存储在 Ghost 目录下 package.json 文件中的 version 字段里,package.json 长这样:

{
  "name": "ghost",
  "version": "0.11.7",
  "description": "Just a blogging platform.",
  ......
}

cat 读出 package.json 的内容,grep 摘出 version 字段所在的行,sed 使用正则表达式取出 version 的值然后赋给 LOCAL_VERSION 变量。

LOCAL_VERSION=$(cat $GHOST_PATH/package.json | grep 'version' | sed 's/.*"version": "\(.*\)".*/\1/g')  

最新版本从 Github 获取,因为 Github 提供了 API,获取版本号比较方便。使用 API 中的 Get the latest release 方法可以获得最新的 Release 版本。

GET /repos/:owner/:repo/releases/latest  

返回的数据是和本地的 package.json 一样是 json 格式的,使用同样的方法取出版本号,只不过这次是在 tag_name 字段。

REMOTE_VERSION=$(curl -s https://api.github.com/repos/TryGhost/Ghost/releases/latest | grep 'tag_name' | sed 's/.*"tag_name": "\(.*\)".*/\1/g')  

然后就是比较两个版本,由于 Ghost 的版本已经到了 0.11.*,直接比较大小有些麻烦(如果直接用字符串比较,0.11.2 比 0.11.1 大,但是却比 0.9.2 小),所以按照只要版本号不一致,就是服务端有新版本的方法来判断。所以这个脚本不适用于测试版用户(测试版可能比服务端版本新)。

if [ "${LOCAL_VERSION}" == "${REMOTE_VERSION}" ]  
then  
......
fi  
备份博客数据

这是一个比较麻烦的地方,Ghost 的数据分为两部分,博文数据放在数据库中(sqlite 或 Mysql),静态资源放在 content 目录下。如果需要从数据库读取博文数据,还要判断用户的数据库类型,比较麻烦,所以直接用 Ghost 的备份接口。

在 Ghost 后台选择 Export ,从 Chrome 控制台可以抓到备份数据的接口是 GET /ghost/api/v0.1/db/,通过 url 中 access_token 字段验证身份。通过登录可以拿到access_token,同样从 Chrome 控制台找到登录的接口 POST /ghost/api/v0.1/authentication/token/,需要注意的是,登录的时候 POST 的字段不仅仅有用户名密码,还有 client_idclient_secret 两个字段。client_id 好像都是 ghost-adminclient_secert 是每个 Ghost 服务都不一样的。这两个字段可以从 signin 页面的 <head> 部分获取到。

所以导出博文数据的步骤具体是这样的:

从 signin 页面获取 client_idclient_secert

GHOST_CLIENTID=$(curl -s "${GHOST_SIGNIN_URL}" | grep 'clientId' | sed 's/.*content="\(.*\)".*".*".*/\1/g')  
GHOST_CLIENTSECERT=$(curl -s "${GHOST_SIGNIN_URL}" | grep 'clientSecret' | sed 's/.*content="\(\w*\)".*/\1/g')  

登录 Ghost 拿到 access_token

GHOST_TOCKEN=$(curl -s -d "grant_type=password&username="${GHOST_ADMIN_USER}"&password="${GHOST_ADMIN_PASS}"&client_id="${GHOST_CLIENTID}"&client_secret="${GHOST_CLIENTSECERT}"" "${GHOST_AUTH_URL}" | sed 's/.*"access_token":"\(\w*\)".*/\1/g')  

通过 export 接口导出备份

curl -s "${GHOST_EXPORT_URL}"?access_token="${GHOST_TOCKEN}" -o "${UPDATE_TMP}"/ghost-backup-"${DATE}"/data.json  

然后把 content 目录和 config.js (Ghost 的部分设置)拷贝出来,压缩一下就完成了备份工作

cp "${GHOST_PATH}"/config.js "${BACKUP_NAME}"/config.js  
cp -r "${GHOST_PATH}"/content "${BACKUP_NAME}"/content  
tar -zcf "${BACKUP_PATH}"/"${BACKUP_NAME}".tar.gz "${BACKUP_NAME}"  
下载最新版本,覆盖旧版本

同样是从 Github 下载而非 Ghost.org ,这里没什么可说的,参考官方的升级指南就行。

curl -LOs https://github.com/TryGhost/Ghost/releases/download/"${REMOTE_VERSION}"/Ghost-"${REMOTE_VERSION}".zip  
unzip -o Ghost-"${REMOTE_VERSION}".zip -d ghost-temp > /dev/null  
rm -rf "${GHOST_PATH}"/core  
cp -R core "${GHOST_PATH}"  
cp index.js *.json "${GHOST_PATH}"  
更新依赖,重启服务

更新一下 Node 的依赖,然后重启一下 Ghost 服务,就更新完成了。

chown -R ghost:ghost *  
"${NPM}" install --production &> /dev/null 
${GHOST_RESTART} > /dev/null 
结束

前边的代码省略了很多非关键操作,完整代码已经传到 Github