Created
May 26, 2015 16:25
-
-
Save crossai-2033/3f7ee1c299c445aa0bc8 to your computer and use it in GitHub Desktop.
发布脚本执行文件
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /bin/bash | |
########################################################################### | |
# 配置项 | |
# include lib | |
# 获取当前deploy脚本的路径 | |
this_file=`pwd`"/"$0 | |
# 通过dirname获取当前部署脚本所在的目录 -- deploy目录 | |
this_dir=`dirname $this_file` | |
# 通过目录引入当前目录下对应的deploy_conf.sh这个配置文件。"." ==> source命令,直接将文件内容引用到当前shell环境中 | |
. $this_dir/deploy_conf.sh | |
########################################################################### | |
# 帮助 | |
# $# ==> 获取调用脚本的参数数量 | |
# 逻辑: 如果参数小于1 || 第一个参数为-h || 第一个参数为--help | |
# 那么进入该if逻辑 $0 => 当前脚本名称 exit 0 => 正常退出脚本 | |
if [ $# -lt 1 ] || [ "-h" = "$1" ] || [ "--help" = "$1" ] | |
then | |
echo "用法: $0 FILE1 [ FILE2 ... ]"; | |
echo "FILE* : 需要上传的文件/目录;注意:每一个文件必须是相对于 $PROJECT_HOME 根目录的相对路径" | |
exit 0; | |
fi | |
########################################################################### | |
# Lets go | |
# 开始进入正常的脚本处理逻辑 | |
# 判别本机的操作系统类型,FreeBSD 与 Linux 有些命令不同 | |
# `uname -s` => 将uname -s获得的内容捕获并赋给变量LOCAL_OS. 如:Linux | |
LOCAL_OS=`uname -s` | |
if [[ "$LOCAL_OS" == *BSD ]] | |
then | |
test | |
else | |
# Linux | |
test | |
fi | |
# 设定deploy目录DEPLOY_DIR,$HOME=>/home/xxx/deploy | |
DEPLOY_DIR="$HOME/deploy" | |
# 每次部署都清空后重新建立一次 /home/xxx/deploy 目录 | |
rm -rf $DEPLOY_DIR && mkdir -p $DEPLOY_DIR | |
# -z 表示为空 如果$ENV_BETA为空的话 | |
if [ -z "$ENV_BETA" ] | |
then | |
# 设定部署目录下面的工程目录 /home/xxx/deploy/xxx | |
PROJECT_HOME="$DEPLOY_DIR/$prj_nam" | |
# 根据repository参数来确定使用svn还是git,目前基本上都开始使用git了 | |
if [ $repository = "svn" ] | |
then | |
cecho "=== export chunk from svn ===" $c_notify | |
svn export $svn $PROJECT_HOME > /dev/null 2>&1 | |
prj_version=`svn --xml info $svn | grep 'revision' | head -1 | awk -F '"' '{ print $2 }'` # 获取当前 SVN 的版本" | |
elif [ $repository = "git" ] | |
then | |
# cecho 函数为自定义函数,主要是给终端加入颜色色值 | |
cecho "=== export master from git ===" $c_notify | |
# 从对应的git仓库拉取最新的master分支,并将该工程代码放入到deploy目录下 | |
# 对应该工程的命令为 git clone -b master git@xxx/xxx/xxx /home/liangchao/xxx/deploy | |
git clone -b master $git $PROJECT_HOME > /dev/null 2>&1 | |
# 进入到/home/xxx/deploy/xxx 目录下做以下两件事情 | |
# 1. 通过git命令拉取最新一条日志,然后通过awk 打印出第二列也就是版本号,如:9be9b0f5f34bb43d534df9d9448546b28abe7d3f | |
cd $PROJECT_HOME | |
prj_version=`git log -1 | head -1 | awk '{print $2}'` # 获取当前 GIT 的版本" | |
# 2. 删除.git目录,即让deploy下面的目录变为一个纯净的裸目录 | |
rm -rf .git | |
# 3. cd - 退回到上次操作的目录, > /dev/null 2>&1 将错误日志写入到垃圾桶中 | |
cd - > /dev/null 2>&1 | |
else | |
cecho "=== repository error, usage svn or git ===" $c_error | |
exit | |
fi | |
else | |
# beta 从 $PROJECT_HOME 中取得代码 | |
prj_version="beta"; | |
fi | |
############################################################################################################################## | |
# 以上代码完成了拉取最新git仓库代码到/home/xxx/deploy/目录下,并获取了版本prj_version,而且删除了.git目录,将要发布的目录做了纯洁化处理 # | |
############################################################################################################################## | |
# 获取项目整个目录的长度 wc -m 获取字符长度,但其实会多一位 因为echo含有回车 用echo -n更好 | |
PROJECT_HOME_LEN=`echo "$PROJECT_HOME/" | wc -m | bc` | |
# 读出所有的文件,并过滤黑名单" | |
files=""; | |
# 如果参数不为空,也就是如果有需要发布的文件 | |
while [ $# -ne 0 ] | |
do | |
# 判断系统 | |
if [[ "$LOCAL_OS" == *BSD ]] | |
then | |
file=`echo "/usr/bin/find -E $PROJECT_HOME/$1 -type f -not -regex '$blacklist' | cut -c '$PROJECT_HOME_LEN-1000' | xargs echo" | sh` | |
else | |
# 找出对应的文件,排除黑名单,然后通过cut -c 按照字符截取,提取出真实使用的路径 => 截取低40-1000的字节 | |
file=`echo "/usr/bin/find $PROJECT_HOME/$1 -regextype posix-extended -type f -not -regex '$blacklist' | cut -c '$PROJECT_HOME_LEN-1000' | xargs echo" | sh` | |
fi | |
# 然后拼接成文件列表 | |
files="${files}${file} " | |
# 通过shift来剔除参数,终结while循环 | |
shift | |
done | |
# expr有模式匹配功能。可以使用expr通过指定冒号选项计算字符串中字符数。.*意即任何字符重复0次或多次 | |
# 这个是用模式匹配全部是空格的个数,如果不等于0个,就表示如果文件为空,那么就没有文件,就退出 | |
# ============》此逻辑待求证?为什么不用.*判断 如果等于空呢? | |
if [ 0 -ne `expr "$files" : ' *'` ]; then | |
cecho "\n没有找到要上传的文件,请调整输入参数" $c_error | |
exit 1; | |
fi | |
# 确认文件 | |
cecho "\n=== 上传文件列表 === \n" $c_notify | |
no=0; | |
for file in $files | |
do | |
no=`echo "$no + 1" | bc` | |
cecho "$no\t$file"; | |
done | |
echo "" | |
# deploy_confirm函数,通过read来确认是否要上传文件 | |
deploy_confirm "确认文件列表?" | |
if [ 1 != $? ]; then | |
exit 1; | |
fi | |
# 源文件打包 | |
cecho "\n=== 文件打包 === \n" $c_notify | |
time=`date "+%Y%m%d%H%M%S"` | |
src_tgz="$HOME/patch.${prj_version}.${USER}.${time}.tgz" | |
# 注意:-C dir参数的作用在于改变工作目录,其有效期为该命令中下一次-C dir参数之前。 | |
# 将tar的工作目录从当前目录改为/home/xxx/deploy,将该目录中的$files文件(不带绝对路径)压缩到$src_tgz中 | |
tar cvfz $src_tgz -C $PROJECT_HOME $files > /dev/null 2>&1 | |
if [ ! -s "$src_tgz" ]; then | |
cecho "错误:文件打包失败" $c_error | |
exit 1 | |
fi | |
############################################################################################################################################################ | |
# 以上代码完成了将待上线的文件打包到/home/xxx$src_tagz ==> patch.5b5f0cbb79e2d5cca018872a1213b470730ba97b.xxx.20150526225247.tgz # | |
############################################################################################################################################################ | |
# 进入部署阶段 | |
hosts="$online_clusters" | |
cecho "\n=== 开始部署 ===" $c_notify | |
# 同步" | |
host1=""; | |
host1_src=""; | |
# 循环所有线上机器列表 | |
for host in ${hosts} | |
do | |
cecho "\n=== ${host} ===\n" $c_notify | |
# 获取用户所对应的$host机器当前对应的文件 如:/home/xxx/xxx.xxx.xxx.tgz | |
online_src="/home/$ssh_user/${USER}.$prj_nam.$host.tgz" | |
# 登录线上机,到对应目录下,找到对应文件,打包到线上机器的/home/xxx/xxx.xxx | |
$SSH $host tar cvhfz $online_src -C $dst $files > /dev/null 2>&1 | |
# 将线上机器的旧文件打包后,SCP到对应用户sync360下面一份。这样本地的/home/xxx/xxx.xxx实际就是当前线上机器的旧文件 | |
$SCP $host:$online_src $online_src > /dev/null 2>&1 | |
# /home/xxx/deploy/online/xxx | |
local_online="$DEPLOY_DIR/online/$host" | |
# 清空并创建对应的online目录和对应机器的目录层级xxx | |
rm -rf $local_online && mkdir -p $local_online | |
# don’t extract file modified time | |
# 解压当前线上的旧文件到online目录下/home/xxx/deploy/online/xxx | |
sudo tar mxz -f $online_src -C $local_online | |
# 记录基准主机 | |
if [ "" = "$host1_src" ]; then | |
host1="$host" | |
host1_src="$local_online" | |
fi | |
# 对比文件的 SVN 版本与线上版本 | |
cecho "\t--- 逐个文件比较差异 ---\n" $c_notify | |
for file in $files | |
do | |
# 确定文件类型,只针对 text 类型 | |
type=`file $PROJECT_HOME/$file | grep "text"` | |
# 如果是非text类型就跳过这个逻辑continue | |
if [ -z "$type" ]; then | |
continue | |
fi | |
cecho "\t$file" | |
# 拿线上当前文件和对应的要上线目录文件做diff | |
# -b或--ignore-space-change 不检查空格字符的不同 | |
# -B或--ignore-blank-lines | |
diffs=`diff -Bb $PROJECT_HOME/$file $local_online/$file` | |
# 如果没有不同就不要确认 | |
if [ -z "$diffs" ]; then | |
continue | |
fi | |
# 如果与基准主机的版本一致,就自动提交 ?? 此段if比较的作用? | |
if [ "$host" != "$host1" ] | |
then | |
tmp=`diff -Bb $host1_src/$file $local_online/$file` | |
if [ -z "$tmp" ]; then | |
continue | |
fi | |
fi | |
# 继续进行 vimdiff | |
sleep 1 | |
vimdiff $PROJECT_HOME/$file ${local_online}/$file | |
deploy_confirm " 修改确认 $file ?" | |
if [ 1 != $? ]; then | |
exit 1; | |
fi | |
done | |
######################################################################################## | |
# 以上代码已经完成了代码线上和线下的diff和vimdiff 如果工程师确认没问题要上线,就会进入到下面的步骤了 # | |
######################################################################################## | |
# 获取将要上线的源文件地址 | |
# patch.5b5f0cbb79e2d5cca018872a1213b470730ba97b.xxx.20150526234855.tgz | |
dst_src_tgz=`basename $src_tgz` | |
# 拷贝到对应线上机器的用户目录下,因为文件加了时间戳,所以不会出现覆盖的情况,但有冗余文件 | |
$SCP $src_tgz $host:~/$dst_src_tgz > /dev/null 2>&1 | |
# 登录到对应线上机器看下拷贝过去的文件是否为空,如果不为空再继续下面逻辑 | |
$SSH $host "test -s ~/$dst_src_tgz" | |
if [ 0 -ne $? ]; then | |
cecho "\t错误:文件上传失败" $c_error | |
exit 1 | |
fi | |
# 备份原始文件 | |
cecho "\n\t--- 备份原始文件 ---\n" $c_notify | |
bak_src_tgz="~$ssh_user/bak.patch.${prj_version}.${USER}.${time}.tgz" | |
$SSH $host tar cvhfz ${bak_src_tgz} -C $dst $files > /dev/null 2>&1 | |
cecho "\t${bak_src_tgz}" | |
$SSH $host "test -s $bak_src_tgz" | |
if [ 0 -ne $? ]; then | |
cecho "\t错误:远程主机原始文件备份失败" $c_error | |
exit 1 | |
fi | |
# 展开源文件 | |
cecho "\n\t--- 部署文件 ---\n" $c_notify | |
$SSH $host "env LC_CTYPE=zh_CN.GB2312 tar mxvfz ~/$dst_src_tgz -C $dst" 2>&1 | sed -e 's/^/ /' | |
if [ 0 != $? ] | |
then | |
cecho "\t错误:部署文件失败" $c_error | |
deploy_confirm " 继续部署?" | |
if [ 1 != $? ]; then | |
exit 1; | |
fi | |
fi | |
# 提示验证部署效果 | |
verify=" --- 上线完毕,执行此命令恢复原始版本: $SSH $host tar mxvfz $bak_src_tgz -C $dst "; | |
if [ "$host" = "$host1" ] | |
then | |
echo "" | |
deploy_confirm "$verify,请验证效果" | |
if [ 1 != $? ]; then | |
exit 1; | |
fi | |
else | |
cecho "\n$verify \n" $c_notify | |
fi | |
done | |
# 清理垃圾 | |
rm -rf $src_tgz | |
if [ ! -z "$DEPLOY_DIR" ] | |
then | |
rm -rf $DEPLOY_DIR | |
fi | |
cecho "\n=== 上线完毕 ===\n" $c_notify |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment