Skip to content

Instantly share code, notes, and snippets.

@imdong
Last active September 22, 2018 06:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save imdong/82f9e9abe4c165329473ad0b9994781f to your computer and use it in GitHub Desktop.
Save imdong/82f9e9abe4c165329473ad0b9994781f to your computer and use it in GitHub Desktop.
Linux
#!/bin/bash
# command 操作锁定接管(可适用任何命令,例子以git为例)
# git lock 手动锁定 锁定后只有自己可以操作,必须手动解锁才可以释放
# git unlock 解除锁定 除锁定者本人,需要提供 lockID 进行解锁
# git checkout|pull|push|merge 操作时会触发临时锁 指定时间内不能继续操作
#
# 安装方法: 移动文件至 /usr/local/bin/git 并添加可执行权限(chmod +x /usr/local/bin/git)
# 然后重启终端即可生效,如未生效,则放置于 ${PATH} 中优先级高于 原 git命令的目录即可
# 同理可用于任意命令的前置锁定
###### 自定义配置区域,不熟悉建议留空即可 ######
# 获取被覆盖的命令名(自身文件名)
COMMAND_NAME=${BASH_SOURCE[0]##*/};
# 需要被锁定接管的参数名(竖线隔开|正则表达式规则)
COMMAND_LOCK_ARGS="checkout|pull|push|merge"
# 临时锁有效时间 (单位: s/秒)
COMMAND_LOCK_TEMP_TIME=120
# 原始被执行文件名(留空自动搜索)
COMMAND_SOURCE_FILE=""
# 定义锁文件名(MacOS下可能没权限,建议使用/tmp/)
COMMAND_LOCK_FILE="/tmp/command_lock_${COMMAND_NAME}"
# 手动锁定参数名
COMMAND_LOCK="lock"
# 手动解锁参数名
COMMAND_UNLOCK="unlock"
# 获取用户session_id (其实就是用户bash pid)
SESSION_ID=${PPID}
###### 自定义配置结束 下面不要更改 ######
# 获取文件最终修改时间
function get_file_modify_time()
{
# 获取检测的文件名
FILE_NAME=${1}
# 根据系统不同分别处理
sysOS=`uname -s`
if [ ${sysOS} == "Darwin" ];then
LOCK_TIME=`stat -f %m "${COMMAND_LOCK_FILE}.pid"`
elif [ ${sysOS} == "Linux" ];then
LOCK_TIME=`stat -c %Y "${COMMAND_LOCK_FILE}.pid"`
else
LOCK_TIME=`stat -c %Y "${COMMAND_LOCK_FILE}.pid"`
fi
return ${LOCK_TIME}
}
# 格式化时间
function format_time2str()
{
# 获取时间
FORMAT_TIME=${1}
FORMAT_STR=${2}
# 根据系统不同分别处理
sysOS=`uname -s`
if [ ${sysOS} == "Darwin" ];then
TIME_STR=`date -r${FORMAT_TIME} "${FORMAT_STR}"`
elif [ ${sysOS} == "Linux" ];then
TIME_STR=`date -d @${FORMAT_TIME} "${FORMAT_STR}"`
else
TIME_STR=`date -d @${FORMAT_TIME} "${FORMAT_STR}"`
fi
return 1
}
# 获取锁id
function lock_get_id()
{
# 设置默认值
LOCK_ID=0;
# 锁定类型 0未锁定 -1手动锁 大于0 锁定时间
LOCK_TYPE=0;
# 检测手动锁
if [ -f "${COMMAND_LOCK_FILE}.lock" ]; then
LOCK_ID=$(cat "${COMMAND_LOCK_FILE}.lock");
LOCK_TYPE=-1;
# 获取锁定创建时间
get_file_modify_time "${COMMAND_LOCK_FILE}.lock"
return 1;
fi
# 检测临时锁
if [ -f "${COMMAND_LOCK_FILE}.pid" ]; then
# 获取临时锁 产生时间
get_file_modify_time "${COMMAND_LOCK_FILE}.pid"
LOCAL_TIME=`date +%s`
# 小于指定时间则锁生效
if [ $[ ${LOCAL_TIME} - ${LOCK_TIME} ] -lt ${COMMAND_LOCK_TEMP_TIME} ]; then
LOCK_ID=$(cat "${COMMAND_LOCK_FILE}.pid");
LOCK_TYPE=$[ $LOCAL_TIME - $LOCK_TIME ];
fi
return 1;
fi
}
# 检查锁文件
function lock_check()
{
# 获取锁ID
lock_get_id;
# 未锁定或为锁定者则 更新锁定 然后返回放行
if [ ${LOCK_ID} -le 0 ] || [ ${LOCK_ID} -eq ${SESSION_ID} ]; then
echo ${SESSION_ID} > "${COMMAND_LOCK_FILE}.pid";
return 0;
fi
# 提示被锁定
format_time2str ${LOCK_TIME} "+%Y-%m-%d %H:%m:%S";
# 根据锁定类型不同显示不同的提示
if [ ${LOCK_TYPE} -lt 0 ]; then
echo "${COMMAND_NAME} 已于 ${TIME_STR} 被手动锁定";
else
echo "未执行,${COMMAND_NAME} 在 ${LOCK_TYPE} 秒内活跃 (${COMMAND_LOCK_TEMP_TIME}秒未操作自动解锁)";
fi
echo "强制解锁执行 ${COMMAND_NAME} ${COMMAND_UNLOCK} ${LOCK_ID}";
exit 0;
}
# 设置锁定
function lock_set()
{
# 检查是否已经被锁定
lock_check;
# 设置锁
echo ${SESSION_ID} > "${COMMAND_LOCK_FILE}.lock";
echo "${COMMAND_NAME} 操作锁定设置成功"
echo "操作完成后记得执行 ${COMMAND_NAME} ${COMMAND_UNLOCK} 进行解锁。"
}
# 操作解锁
function lock_unset()
{
# 获取参数ID
UNLOCK_ID=0;
if [ "${2}" ]; then
UNLOCK_ID=${2}
fi
# 获取锁定ID
lock_get_id;
# 判断是否锁定
if [ ${LOCK_ID} -eq 0 ]; then
echo "${COMMAND_NAME} 未被锁定"
return 0;
fi
# 解锁参数是否正确
if [ ${LOCK_ID} -eq ${SESSION_ID} ] || [ ${LOCK_ID} -eq ${UNLOCK_ID} ]; then
rm -f "${COMMAND_LOCK_FILE}.lock"
rm -f "${COMMAND_LOCK_FILE}.pid"
echo "${COMMAND_NAME} 解除锁定操作成功"
return 1;
else
echo "未能解锁,非锁定者本人操作"
echo "强制解锁执行 ${COMMAND_NAME} ${COMMAND_UNLOCK} ${LOCK_ID}";
fi
}
# 判断命令
case ${1} in
# 手动锁定
${COMMAND_LOCK})
lock_set 1
exit 1
;;
# 手动解锁
${COMMAND_UNLOCK})
lock_unset $@
exit 1
;;
# 通过正则表达式匹配命令是否符合上面的规则
*)
if [[ "${@}" =~ ${COMMAND_LOCK_ARGS} ]]; then
# 检测锁定
lock_check $@
fi
;;
esac
# 如果原始命令留空则遍历目录找能执行的文件
if [ ! "${COMMAND_SOURCE_FILE}" ]; then
PATH_LIST=${PATH//:/ }
for PATH_ITEM in ${PATH_LIST}
do
# 判断文件存在且不是自身
COMMAND_FILE_NAME="${PATH_ITEM}/${COMMAND_NAME}";
if [ -f "${COMMAND_FILE_NAME}" ] && [ "${COMMAND_FILE_NAME}" != "${BASH_SOURCE[0]}" ]; then
COMMAND_SOURCE_FILE="${COMMAND_FILE_NAME}";
break;
fi
done
fi
# 如果为能正确定义原始文件则不在执行 [ ! "${COMMAND_SOURCE_FILE}" ] ||
if [ ! "${COMMAND_SOURCE_FILE}" ]; then
echo "未能找到 ${COMMAND_NAME} 对应的原始文件,请手动配置正确的文件。"
exit;
fi
# 调用原有执行
${COMMAND_SOURCE_FILE} $@
exit $?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment