Skip to content

Instantly share code, notes, and snippets.

@crossai-2033
Created May 26, 2015 16:25
Show Gist options
  • Save crossai-2033/3f7ee1c299c445aa0bc8 to your computer and use it in GitHub Desktop.
Save crossai-2033/3f7ee1c299c445aa0bc8 to your computer and use it in GitHub Desktop.
发布脚本执行文件
#! /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