文档章节

前端发布脚本

开源中国董事会主席
 开源中国董事会主席
发布于 2014/06/03 11:53
字数 1692
阅读 2445
收藏 9
#!/bin/bash
#
# description: 该文件是基于 Git 为版本管理系统的前端自动化发布脚本,也实用与如 PHP、Python 等脚本语言系统。
#              该脚本主要是为了实现 javascript、css 文件的在发布时自动压缩。
#              该脚本是基于 YUI Compressor (http://yui.github.io/yuicompressor/) 来实现 javascript、css 文件的压缩。
#               所以,运行该脚本,需要 Java 环境支持。
#              由于,在 javascript 代码书写不规范的情况下,容易导致压缩后的 javascript 不可用;所以,在生产环境发布之前,一定要经过严格的测试.
#
#              执行流程:(1)如果是第一次发布时,会从 Git 仓库 clone 一份代码到 PROJECT_DIR;或非第一次发布时,会切换到 PROJECT_DIR 执行 git pull 命令;
#                        (2)将当次更新的文件,记录到 UPDATE_LIST_FILE 文件中;
#                        (3)将 javascript 和 css 文件,压缩输出到 WEB_ROOT,非 javascript 和 css 文件或在压缩文件时出错,则 copy 到 WEB_ROOT;
#                        (4)从 WEB_ROOT 下删除已经从 Git 仓库中删除了的文件和目录;
#                        (5)发布完成。
#
#              PROJECT_DIR:项目源目录,WEB_ROOT:网站根目录。之所以,不直接在 WEB_ROOT 下压缩,是为了,避免压缩后的文件与 Git 仓库中更新下来的文件产生冲突。
#

set -e

PROJECT_NAME=""
PROJECT_DIR=""
WEB_ROOT=""
LOG_DIR="/var/log/"
YUICOMPRESSOR_JAR="/home/admin/script/release/lib/yuicompressor.jar"

CHARSET="UTF-8"
GIT_CHAESET="UTF-8"

GIT_PROTOCOL=${GIT_PROTOCOL-"ssh"}
GIT_HOST=${GIT_HOST-""}
GIT_PORT=${GIT_PORT-0}
GIT_USER=${GIT_USER-""}
BRANCH=${BRANCH-"master"}
# WEB_ROOT 所属用户组
GROUP=${GROUP-"nobody"}
# WEB_ROOT 所属用户
USER=${USER-"nobody"}

OPTIONS=""

note() {
    printf "$*\n" 1>&2;
}

warning() {
    printf "warning: $*\n" 1>&2;
}

error() {
    printf "error: $*\n" 1>&2;
    exit 1
}

usage() {
    me=`basename "$0"`

    echo "Usage: $me {release|rollback|h|help} [options]"
    echo "       -p, --project-name=项目名称        Git 项目名称"
    echo "       --project-dir=项目路径                项目项目源码存放路径"
    echo "       --web-root=WEB ROOT                项目关联网站根目录"
    echo "       --charset=项目字符集                项目文件字符集"
    echo "       --git-charset=Git 字符集            Git 终端显示字符集"
    echo "       --git-protocol=Git 协议            Git 请求协议"
    echo "       --git-host=Git 主机名称            Git 主机名称"
    echo "       --git-port=Git 主机端口            Git 主机端口"
    echo "       --git-user=Git 用户名                Git 用户名"
    echo "       -b, --branch=分支名称                当前使用分支"
    echo "       -g, --group=文件所属组                WEB ROOT 文件所属用户组"
    echo "       -u, --user=文件所说用户            WEB ROOT 文件所属用户"
    echo "       --log-dir=日志目录                    log direetory"

    exit 1
}

check() {
    if [ -z "$PROJECT_NAME" ]; then
        error "project name could not be empty"
    fi

    if [ -z "$PROJECT_DIR" ]; then
        error "project direetory could not be empty"
    fi

    if [ -z "$WEB_ROOT" ]; then
        error "project web root could not be empty"
    fi
}

update_files_init() {
    local arg=$1
    local path="$PROJECT_DIR/$arg"

    if [ -d "$path" ]; then
        local files=`ls "$path"`

        for file in $files
        do
            local _path="$path/$file"
            local temp="$file"

            if [ ! "$arg" == "" ]; then
                temp="$arg/$temp"
            fi

            if [ -d "$_path" ]; then
                update_files_init "$temp"
            else
                echo "$temp" >> $UPDATE_LIST_FILE
            fi
        done
    elif  [ -f "$path" ]; then
        echo "$arg" >> $UPDATE_LIST_FILE
    else
        warning "$path is not exists";
    fi

    return 0
}

condense() {
    local type=$1
    local source_file=$2
    local target_file=$3
    local MSG="Compression "

    if [ "$type" == "js" ]; then
        MSG=$MSG"javascript"
    else
        MSG=$MSG"css"
    fi
    MSG=$MSG" file $source_file to $target_file"

    note $MSG" success"
    java -jar ${YUICOMPRESSOR_JAR} --type ${type} --charset ${CHARSET} "$source_file" -o "$target_file" || { warning "$MSG failure"; note "so copy $source_file to $target_file"; \cp $source_file $target_file; }

    chown ${USER}:${GROUP} "$target_file"
}

operate() {
    local file=$1

    if [ ! -z "$file" ]; then
        local source_file="$PROJECT_DIR/$file"
        local target_file="$WEB_ROOT/$file"
        local target_dir=`dirname "$target_file"`

        if [ -f "$source_file" ]; then
            mkdir -p "$target_dir" || { warning "create target directory $target_dir failure"; }

            if [[ "$source_file" =~ .js$ ]]; then
                condense "js" "$source_file" "$target_file"
            elif [[ "$source_file" =~ .css$ ]]; then
                condense "css" "$source_file" "$target_file"
            else
                note $"Copy file $source_file to $target_file"
                cp "$source_file" "$target_file"
            fi

            chown ${USER}:${GROUP} "$target_file"
        fi
    fi
}

delete_file() {
    local file=$1

    if [ ! -z "$file" ]; then
        local source_dir=`dirname "$PROJECT_DIR/$file"`
        local target_file="$WEB_ROOT/$file"
        local target_dir=`dirname "$target_file"`

        if [ ! -d "$source_dir" ]; then
            note "clear directory $target_dir"
            rm -fR "$target_dir"
        else
            note "Delete file $target_file"
            rm -f "$target_file"
        fi
    fi
}

release() {
    note "Release project $PROJECT_NAME";

    check

    local git_dir=$PROJECT_DIR"/.git"
    if [ ! -d $git_dir ]; then
        if [ -z "$GIT_PROTOCOL" ]; then
            error "project git protocol could not be empty"
        fi

        if [ -z "$GIT_HOST" ]; then
            error "project git host could not be empty"
        fi

        if [ -z "$GIT_PORT" ]; then
            error "project git port could not be empty"
        fi

        if [ -z "$GIT_USER" ]; then
            error "project git username could not be empty"
        fi

        note "initialize project $PROJECT_NAME with source direetory $PROJECT_DIR and WEB ROOT $WEB_ROOT";
    fi

    mkdir -p $LOG_DIR || { error "create log directory $LOG_DIR failure"; }

    if [ -f $UPDATE_LIST_FILE ]; then
        rm $UPDATE_LIST_FILE || { error "Remove $UPDATE_LIST_FILE failure"; }
    fi

    if [ -d $PROJECT_DIR ]
    then
        cd $PROJECT_DIR
        git pull origin ${BRANCH} > $RELEASE_LOG || { error "git pull code failure"; }

        local temp=`grep 'Already up-to-date' $RELEASE_LOG`
        if [ "$temp" == "" ]; then
            note "List update files";
        else
            warning "Already up-to-date";
            exit 1;
        fi

        note "checkout $BRANCH branch"
        git checkout ${BRANCH}
        sleep 1
        git diff-tree -r --name-status --no-commit-id ORIG_HEAD HEAD > $UPDATE_LIST_FILE

        while read i;
        do
            temp=`echo $i|awk -F '^A' '{gsub("\"", "", $2); gsub(/^ *| *$/, "", $2); print $2;}'`;
            operate "$temp";
        done < $UPDATE_LIST_FILE

        while read i;
        do
            temp=`echo $i|awk -F '^M' '{gsub("\"", "", $2); gsub(/^ *| *$/, "", $2); print $2;}'`;
            operate "$temp";
        done < $UPDATE_LIST_FILE

        while read i;
        do
            temp=`echo $i|awk -F '^D' '{gsub("\"", "", $2); gsub(/^ *| *$/, "", $2); print $2;}'`;
            delete_file "$temp";
        done < $UPDATE_LIST_FILE
    else
        cd `dirname "$PROJECT_DIR"`

        local project_git_url="$GIT_PROTOCOL://$GIT_USER@$GIT_HOST:$GIT_PORT/$PROJECT_NAME"
        git clone ${project_git_url} > $RELEASE_LOG || { error "git clone $PROJECT_NAME form $GIT_URL error"; }

        cd $PROJECT_DIR

        note "Checkout $BRANCH branch"
        git checkout ${BRANCH}
        sleep 1

        note "List update files"

        update_files_init "" || { error "update files init failure"; }

        local files=`cat $UPDATE_LIST_FILE`

        for file in $files
        do
            operate "$file"
        done

        chown ${USER}:${GROUP} "$WEB_ROOT"
    fi
}

rollback() {
    note "Rollback project $PROJECT_NAME";

    check

    if [ "$OPTIONS" == "" ]; then
        error "rollback options could not be empty";
    else
        cd $PROJECT_DIR

        note "Checkout $BRANCH branch"
        git checkout ${BRANCH}

        sleep 1

        git reset --hard $OPTIONS
        git diff-tree HEAD HEAD^ -r --name-status > $ROLLBACK_LIST_FILE

        while read i;
        do
            temp=`echo $i|awk -F '^A' '{gsub("\"", "", $2); gsub(/^ *| *$/, "", $2); print $2;}'`;
            delete_file "$temp";
        done < $ROLLBACK_LIST_FILE

        while read i;
        do
            temp=`echo $i|awk -F '^M' '{gsub("\"", "", $2); gsub(/^ *| *$/, "", $2); print $2;}'`;
            operate "$temp";
        done < $ROLLBACK_LIST_FILE

        while read i;
        do
            temp=`echo $i|awk -F '^D' '{gsub("\"", "", $2); gsub(/^ *| *$/, "", $2); print $2;}'`;
            operate "$temp";
        done < $ROLLBACK_LIST_FILE
    fi
}

ACTION=$1
shift

args_count=$#
args_count=`expr $args_count - 1`
i=0

while test $i -le $args_count ;
do
    case "$1" in
        -p=*)
            PROJECT_NAME=${1##-p=}
            shift
            i=`expr $i + 1`
            ;;
        --project-name=*)
            PROJECT_NAME=${1##--project-name=}
            shift
            i=`expr $i + 1`
            ;;
        --project-dir=*)
            PROJECT_DIR=${1##--project-dir=}
            shift
            i=`expr $i + 1`
            ;;
        --web-root=*)
            WEB_ROOT=${1##--web-root=}
            shift
            i=`expr $i + 1`
            ;;
        --charset=*)
            CHARSET=${1##--charset=}
            shift
            i=`expr $i + 1`
            ;;
        --git-charset=*)
            GIT_CHAESET=${1##--git-charset=}
            shift
            i=`expr $i + 1`
            ;;
        --git-protocol=*)
            GIT_PROTOCOL=${1##--git-protocol=}
            shift
            i=`expr $i + 1`
            ;;
        --git-host=*)
            GIT_HOST=${1##--git-host=}
            shift
            i=`expr $i + 1`
            ;;
        --git-port=*)
            GIT_PORT=${1##--git-port=}
            shift
            i=`expr $i + 1`
            ;;
        --git-user=*)
            GIT_USER=${1##--git-user=}
            shift
            i=`expr $i + 1`
            ;;
        -b=*)
            BRANCH=${1##-b=}
            shift
            i=`expr $i + 1`
            ;;
        --branch=*)
            BRANCH=${1##--branch=}
            shift
            i=`expr $i + 1`
            ;;
        -g=*)
            GROUP=${1##-g=}
            shift
            i=`expr $i + 1`
            ;;
        --group=*)
            GROUP=${1##--group=}
            shift
            i=`expr $i + 1`
            ;;
        -u=*)
            USER=${1##-u=}
            shift
            i=`expr $i + 1`
            ;;
        --user=*)
            USER=${1##--user=}
            shift
            i=`expr $i + 1`
            ;;
        --log-dir=*)
            LOG_DIR=${1##--log-dir=}
            shift
            i=`expr $i + 1`
            ;;
        -h|--help)
            usage
            exit 0
            ;;
        *)
            case "$ACTION" in
                rollback)
                    OPTIONS=$OPTIONS" "$1
                    shift
                    i=`expr $i + 1`
                    ;;
                *)
                    usage
                    exit 0
                    ;;
            esac
    esac
done

# 设置编码和文件名允许中文等字符  
git config --global core.quotepath false         # 设置文件名允许中文等字符
git config --global i18n.logoutputencoding ${GIT_CHAESET} # 设置 git log 输出时编码
export LESSCHARSET=${GIT_CHAESET}

RELEASE_LOG=$LOG_DIR"/release.log"
UPDATE_LIST_FILE=$LOG_DIR"/update_list.txt"
ROLLBACK_LIST_FILE=$LOG_DIR"/rollback_list.txt"

case "$ACTION" in
    release|rollback)
        $ACTION
        ;;
    *)
        echo "Usage: $0 {release|rollback}"
        ;;
esac

exit 0

#!/bin/bash

PROJECT_NAME="project"
DOMAIN="www.example.com"
HOME_ROOT="/data/projects"
SOURCE_DIR=$HOME_ROOT"/source"
PROJECT_DIR=$SOURCE_DIR"/"$PROJECT_NAME
WEB_ROOT="/data/htdocs/"$DOMAIN
LOG_DIR=$HOME_ROOT"/logs/"$PROJECT_NAME

GIT_HOST=${GIT_HOST-"git host"}
GIT_PORT=${GIT_PORT-git port}
GIT_USER=${GIT_USER-"git user"}
BRANCH="master"

CHARSET="UTF-8"
GIT_CHARSET="UTF-8"

GROUP="www"
USER="www"

RELEASE_EXCE=$(cd "$(dirname "$0")"; pwd)
RELEASE_EXCE=$RELEASE_EXCE"/release_static.sh"

ACTION=$1
shift

args_count=$#
args_count=`expr $args_count - 1`
OPTION=""
i=0

while test $i -le $args_count ;
do
    OPTION=$OPTION" "$1
    shift
    i=`expr $i + 1`
done

case "$ACTION" in
    release)
        bash ${RELEASE_EXCE} release -p="$PROJECT_NAME" --project-dir="$PROJECT_DIR" --branch="$BRANCH" --web-root="$WEB_ROOT" --git-protocol="ssh" --git-host="$GIT_HOST" --git-port=$GIT_PORT --git-user="$GIT_USER" --group="$GROUP" --user="$USER" --charset="$CHARSET" --git-charset="$GIT_CHARSET" --log-dir="$LOG_DIR"
        ;;
    rollback)
        bash ${RELEASE_EXCE} rollback -p="$PROJECT_NAME" --project-dir="$PROJECT_DIR" --branch="$BRANCH" --web-root="$WEB_ROOT" --group="$GROUP" --user="$USER" --charset="$CHARSET" --git-charset="$GIT_CHARSET" --log-dir="$LOG_DIR" $OPTION
        ;;
    *)
        bash ${RELEASE_EXCE} --help
        ;;
esac

exit 0

© 著作权归作者所有

共有 人打赏支持
开源中国董事会主席

开源中国董事会主席

粉丝 111
博文 20
码字总数 14304
作品 2
成都
高级程序员
加载中

评论(9)

开源中国董事会主席
开源中国董事会主席
修改了两处错误
blu10ph
blu10ph
h~
开源中国首席发言人
开源中国首席发言人
好!
许雷神
许雷神
好标题
开源中国董事会主席
开源中国董事会主席

引用来自“Bery”的评论

好文章,我只看了一下标题
不是小白
不是小白
好文章,我连标题都没看
花花兽
花花兽
好文章,我连标题都没看
后山未悟道之人
后山未悟道之人

引用来自“Bery”的评论

好文章,我只看了一下标题
嗯,是个好标题
不是胖子
不是胖子
好文章,我只看了一下标题
真▪一行代码完成从前端代码build到部署线上

在经历了6,7个项目同时开工,频繁发布测试 ,不得不学会一点偷懒的小技巧来提高效率了,所以这篇文章要讲的就是如何更加优化发布流程。 工作以来,经历了build后,然后用上传服务器完成部署。...

TimeFly
08/10
0
0
使用python构建一个简单的发布系统

一、流程 通过前端上传要发布的压缩包,逻辑端获取后将压缩包分发到远程服务器上,并执行远程服务器上使用shell编写的发布脚本,实现代码发布。 二、前端文件上传代码

yaoliang833
2016/11/22
0
0
阿里·云效平台成2016北京QCon大会亮点

4月21~23日,2016年北京QCon大会在北京国际会议中心举行,大会邀请了互联网领域的大咖分享国内外技术交流的最新趋势资讯,涉及自动化运维、移动开发挑战、移动测试技术、大数据平台架构等精彩...

云效平台
2016/04/21
0
0
我的架构经验系列文章 - 前端架构

框架层面:近几年前端发展很快,前端之所以叫前端因为前端是已经可以独立成为一种职业了,js也不再是十年前的玩具了,以前富客户端RIA的应用可能会用flash/flex或是silverlight,现在可以使用...

fadevd
2014/07/29
21
0
前端模块化解决方案--fis-pure

fis-pure 是基于FIS的纯前端模块化解决方案pure pure是基于FIS二次封装能力封装而成的解决方案,可以直接使用,也可以参考fis-pure自行封装或组合使用插件来构建属于自己的一体化解决方案。 ...

叶秀兰
2014/07/28
3.7K
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

windbg调试C源码级驱动

联机方式不多说了。我博客里有,英文的。 windbg联机文档 https://docs.microsoft.com/zh-cn/windows-hardware/drivers/debugger/debug-universal-drivers---step-by-step-lab--echo-kernel......

simpower
36分钟前
0
0
redis快照和AOF简介

数据持久化到硬盘:一是快照(snapshotting),二是只追加文件(append-only file AOF) 快照 核心原理:redis某个时间内存内的所有数据写入硬盘 场景:redis快照内存里面的数据 1. 用户发送bgsav...

拐美人
37分钟前
0
0
这个七夕,送你一份程序员教科书级别的告白指南

给广大爱码士们的高能预警: 今天,就是七夕了…… (单身非作战人群请速速退场!) 时常有技术GG向个推君抱怨 经过网民多年的教育 以及技术人持之以恒的自黑 冲锋衣狂热分子·格子衫骨灰级粉...

个推
42分钟前
0
0
python爬虫日志(15)cookie详解

转载:原文地址 早期Web开发面临的最大问题之一是如何管理状态。服务器端没有办法知道两个请求是否来自于同一个浏览器。那时的办法是在请求的页面中插入一个token,并且在下一次请求中将这个...

茫羽行
43分钟前
0
0
qlv视频格式转换器

  腾讯视频中的视频影视资源有很多,小编经常在里面下载视频观看,应该也有很多朋友和小编一样吧,最近热播的电视剧也不少,如《香蜜沉沉烬如霜》、《夜天子》还有已经完结的《扶摇》,这么...

萤火的萤火
46分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部