Xiuquan's Blog


  • 首页

  • 归档

  • 关于

我写编译脚本

发表于 2017-03-20

需求:做持续集成,一个核心点为编译脚本的编写,本文根据项目实际经验做一些总结。

help的重要性

一个shell脚本,如何快速上手,help至关重要,例如linux下的shell命令,通过man或–help 通常可以快速了解这个指令的用法,写编译脚本也不例外,因为很有可能后期用这个脚本的人不是当初写脚本的人。一个好的help 应该告诉使用者 如何传参数,参数的解释以及一些基本用法等。

参数解析

编译脚本应该可以适应不同的任务,不建议一个脚本对应一个编译任务,例如如果你需要编译一个debug版本的apk或者一个release版本的apk,不好的实践是你写了一个build_debug.sh 又写了一个build_release.sh, 而建议的做法是抽象到一个shell中去,做封装和参数解析,这样便于维护和扩展。如你可以这样写build.sh -t debug/release等,通过-t参数指定编译任务。shell里面的对于参数解析可以温习getopts这个指令,请自行搜索不再赘述。

参数有效性判定

在安全领域有句话叫不要相信用户的输入,对于一个脚本来说,你同样需要对用户输入做有效性校验,例如你的这个脚本只接收这些参数,其他都忽略,那么脚本中就得做相应的判断

[ "$buildType" != "debug" -a "$buildType" != "release" ]  && echo "buildType needs to be debug or release" && usage

以上例子是对参数做判定,只能接受”debug”或”release”其他输入就会提示用户。
当然还有参数非空判断,见以下例子:

para_check()
{
    echo "parameter error, please check......"
    echo 
    exit 1
}


[ -z "$1" ] && para_check

日志的技巧

如果有报错,看日志是最有效的做法,shell脚本中日志也必不可少,比如关键函数的执行轨迹,异常之后的日志输出,执行时间的记录等。

build()
{
    [ $# != 2 ] && para_check
    echo "------build begin------"
    TIME_BEFORE_UNIT=`date +%s`
    rm -rf ./output
    env_opt "$1"
    compile "$2"
    pwd && ls -lhR ./output

    if [ $? -ne 0 ] ; then
        echo "------build error------";
        return -1;
    fi

    TIME_AFTER_UNIT=`date +%s`
    UNIT_TIME=$(($TIME_AFTER_UNIT-$TIME_BEFORE_UNIT))
    echo "------compile elapse time:" $UNIT_TIME "s"
    echo "------build end------"

    return 0;
}

这个例子记录了shell的执行开始时间,结束时间,执行路径等,可以方面后期debug和维护。

编译环境

这个是一个容易忽略的点,但是往往再问题定位时会给出一个思路,例如同样的代码用java1.6编译和1.7编译,编译错误很有可能是不一样的,同时一些语言自身也在不断发展,例如gradle迭代速度就非常块,经常会有稳定性,性能提升方面的改进,当你发现编译的主逻辑没有变化,但是不同的机器,编译出来的结果差异很大时,需要考虑编译环境的问题,我的习惯做法是在编译脚本开始打印出软件的版本,如java或gradle的version等。
另外一点:使你定义的环境变量生效,简单的做法先定义好相关的path 和环境变了到profie,然后source ~/.bash_profile使其生效。

一个完整的例子

#!/bin/bash
#/***************************************************************************
# * 
# * Copyright (c) 2016 xxx.com, Inc. All Rights Reserved
# * 
# **************************************************************************/

#/**
# * @file build_ci.sh
# * @author xxx@xx.com
# * @date 2016/11/28/
# **/

# 帮助
usage()
{
    echo "-------------------------------------------------------------------------------"
    echo "Usage: build_ci.sh [-r] [-t debug/release] [-f dev/prod] [-a ut/cc] ..."
    echo "-------------------------------------------------------------------------------"
    echo 
    echo "Options:"
    echo " -r Turns the remote cluster compile on, By default, build task is a local build"
    echo " -t Specifies options for build type : debug/release"
    echo " -f Specifies options for flavor : dev/prod "
    echo " -a Specifies options for build task : ut(unit test)/cc(static code check)"
    echo " -s Specifies a android device(get id by exec adb devices)"
    echo " -h Displays usage information for build_ci.sh"
    echo 
    echo "Examples:"
    echo "sh build_ci.sh -t debug -f dev"
    echo "sh build_ci.sh -t debug -f prod"
    echo "sh build_ci.sh -t release -f dev"
    echo "sh build_ci.sh -t release -f prod"
    echo "sh build_ci.sh -t debug -f dev -s B2T0216513013613 -a ut"
    echo "sh build_ci.sh -t debug -f dev -s B2T0216513013613 -a cc"
    echo 
    exit 1
}

para_check()
{
    echo "parameter error, please check......"
    echo 
    exit 1
}

checkVersion()
{
    java -version
    gradle -v
}

# 编译集群环境准备
env_opt()
{
    echo "set build env......"
    [ -z "$1" ] && para_check
    echo "is_remote_build:$1"
    if [ "$1" == true ]; then
        echo "set remote build env"
        export BUILD_KIT_PATH=/home/scmtools/buildkit
        echo "BUILD_KIT_PATH:"$BUILD_KIT_PATH
        export JAVA_HOME=$BUILD_KIT_PATH/jdk-1.8u92
        export GRADLE_HOME=$BUILD_KIT_PATH/gradle/gradle-3.2.1
        export PATH=$JAVA_HOME/bin:$GRADLE_HOME/bin:$PATH

    fi
    echo "source ~/.bash_profile>/dev/null 2>&1"
    source ~/.bash_profile>/dev/null 2>&1
    checkVersion
}

# 编译
compile()
{
    [ -z "$1" ] && para_check
    echo $1
    echo "gradle compile begin"
    chmod 755 ./gradlew
    $($1)
    echo "gradle compile end"
}

build()
{
    [ $# != 2 ] && para_check
    echo "------build begin------"
    TIME_BEFORE_UNIT=`date +%s`
    rm -rf ./output
    env_opt "$1"
    compile "$2"
    pwd && ls -lhR ./output

    if [ $? -ne 0 ] ; then
        echo "------build error------";
        return -1;
    fi

    TIME_AFTER_UNIT=`date +%s`
    UNIT_TIME=$(($TIME_AFTER_UNIT-$TIME_BEFORE_UNIT))
    echo "------compile elapse time:" $UNIT_TIME "s"
    echo "------build end------"

    return 0;
}

# 变量初始化
workspace=$(pwd)
is_remote_build=false
buildType="debug"
flavor="prod"
buildAction=""
deviceId=""

[ $# -eq 0 ] && usage

# get options
while getopts "rt:f:a:s:" arg
do
    case $arg in
        r)
          is_remote_build=true
          ;;
        t)
          buildType=$OPTARG
          echo "buildType:$buildType"
          [ "$buildType" != "debug" -a "$buildType" != "release" ] \
          && echo "buildType needs to be debug or release" && usage
          ;;
        f)
          flavor=$OPTARG
          echo "flavor:$flavor"
          [ "$flavor" != "dev" -a "$flavor" != "prod" ] \
          && echo "flavor needs to be dev or prod" && usage
          ;;
        a)
          buildAction=$OPTARG
          echo "buildAction:$buildAction"
          [ "$buildAction" != "ut" -a "$buildAction" != "utup" -a "$buildAction" != "cc" ] \
          && echo "buildAction needs to be ut or cc or utup" && usage
          ;;
        s)
          deviceId=$OPTARG
          echo "deviceId:$deviceId"
          ;;
        ?)
          usage
          ;;
    esac
done

buildType="$(tr '[:lower:]' '[:upper:]' <<< ${buildType:0:1})${buildType:1}"
flavor="$(tr '[:lower:]' '[:upper:]' <<< ${flavor:0:1})${flavor:1}"

build_cmd_header="./gradlew clean "
build_cmd=$build_cmd_header"assemble"$flavor$buildType
device_model="";
device_version="";

if [ ! -z "${deviceId}" ] ; then
    echo "export ANDROID_SERIAL=$deviceId"
    export ANDROID_SERIAL=$deviceId

    echo "adb -s $deviceId shell getprop ro.product.model | xargs"
    echo "adb -s $deviceId shell getprop ro.build.version.release | xargs"

    device_model=$(adb -s $deviceId shell getprop ro.product.model | xargs)
    device_version=$(adb -s $deviceId shell getprop ro.build.version.release | xargs)
fi

if [ ! -z "${buildAction}" -a "${buildAction}" == "ut" ] ; then
    build_cmd=$build_cmd_header"create"$flavor$buildType"CoverageReport"
fi

if [ ! -z "${buildAction}" -a "${buildAction}" == "cc" ] ; then
    build_cmd=$build_cmd_header"assemble"$flavor$buildType" check"
fi

echo "build_cmd:$build_cmd"
build "$is_remote_build" "$build_cmd"

mac下nginx安装及其目录遍历配置

发表于 2017-03-19

背景:mac开发机,本地搭建nginx服务,对服务端存储的文档做展示。

安装nginx

直接通过brew安装

1
brew install nginx

启动nginx

1
nginx

停止nginx

1
nginx -s stop

重新加载nginx

1
nginx -s reload

配置文件遍历

1
2
3
4
5
6
7
8
vi /usr/local/etc/nginx/nginx.conf
# server 节点
location /share {
root /Users/yourusername/dir_needed_share;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}

几个关键点:

  • /share 和root 配置的目录必须是可达到的路径 即/Users/yourusername/dir_needed_share/share 此路径可达,否则访问时会报404
  • autoindex 为必填选型 默认开启
  • autoindex_exact_size off 则会将文件的大小以合适的单位显示M,G等,否则显示字节数

一些文件路径

用brew安装的nginx 一些文件路径不一样需要注意

  • 安装目录

    /usr/local/Cellar/nginx/1.10.3
    
  • 配置文件路径

    /usr/local/etc/nginx/nginx.conf
    
  • 日志文件路径

    /usr/local/var/log/nginx $ ls -lrt
    total 80
    -rw-r--r--  1 staff  admin  29646  3 19 14:45 access.log
    -rw-r--r--  1 staff  admin   6430  3 19 19:11 error.log
    

mac os ftp配置使用实践

发表于 2017-03-19

需求背景:mac的文件系统和移动硬盘的ntfs文件系统不兼容,如何传文件变成了一件有意思的事情,本文将剑走偏锋,通过FTP实现文件传输需求。

启动ftp服务

mac 默认是有ftpd的服务,但是并未开启,需要执行以下命令

1
sudo -s launchctl load -w /System/Library/LaunchDaemons/ftp.plist

服务检查,如果显示server ready,则表示FTP服务已经OK

1
2
3
4
~ :ftp localhost
Trying ::1...
Connected to localhost.
220 ::1 FTP server (tnftpd 20100324+GSSAPI) ready.

这就完了?当然不,这个时候使用client访问的时候,发现默认会显示用户home目录下的所有东西,处于解决强迫症和安全性考虑,需要改一下,那么就继续下面的配置吧!

配置ftp服务

配置哪些用户才能使用ftp

1
2
3
4
5
sudo vi /etc/ftpusers
#内容如下
yourusername allow shareGroup
* deny

简单解释一下:
行1:指定的用户可以访问,并定义的一个class[shareGroup] ,非常重要,后面配置chroot需要。
行2:其他所有用户都拒绝访问。

配置用户的root目录

这个就是解决ftp登录上去之后所能看到的根目录

1
2
3
4
5
sudo vi /etc/ftpd.conf
#内容如下
umask all 022
chroot shareGroup /Users/yourusername/dir

重启ftp服务

1
2
sudo -s launchctl unload -w /System/Library/LaunchDaemons/ftp.plist
sudo -s launchctl load -w /System/Library/LaunchDaemons/ftp.plist

关闭ftp服务

处于安全考虑,用完ftp服务就关了吧,unload即可。

1
sudo -s launchctl unload -w /System/Library/LaunchDaemons/ftp.plist

ftp客户端

  • chrome浏览器 直接ftp://your_ftp_server_ip
  • FlashFXP 一个超级好用的client

github SSH 配置

发表于 2017-03-05

电脑上有公司的git仓库,为了避免和github冲突,新建一对key添加到github中去,
以下是操作步骤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#添加钥匙对
ssh-keygen -t rsa -b 4096 -C "youremail@xxx.com" -f /Users/username/.ssh/github_rsa
一路回车
#注意修改私钥权限
chmod 700 ~/.ssh/github_rsa
#启动ssh-agent
eval "$(ssh-agent -s)"
#将刚才添加的key放到ssh-agent中去
ssh-add -K ~/.ssh/github_rsa
#修改~/.ssh/config
添加
Host github.com
IdentityFile ~/.ssh/github_rsa
pbcopy < ~/.ssh/github_rsa.pub
此时公钥已经复制到剪贴板,在github setting中add ssh key即可

github官方配置指南

hexo博客搭建成功

发表于 2017-03-04

花费3个小时,基于hexo搭建的博客终于成功上线了!
引用参考攻略,谢谢你们的技术分享:

  • hexo简介、安装、部署
  • hexo使用心得(一)
  • hexo使用心得(二)
  • hexo你的博客

一些踩坑记录

hexo DTraceProviderBindings MODULE_NOT_FOUND

虽然不影响使用但是还是逼死强迫症的节奏啊
附解决方案:

1
$ npm install hexo --no-optional

或者重装hexo-cli

1
2
$ npm uninstall hexo-cli -g
$ npm install hexo-cli -g

git 部署报错

总是提示push的权限不对,到了一个错误的帐号,隐约记得之前用过一起其他github帐号push过代码,但是已经改了.ssh/config文件 ssh-add 也修改了,还是不起作用,于是乎google了一把
终于找到一个相近的问题
http://stackoverflow.com/questions/5335197/gits-famous-error-permission-to-git-denied-to-user

问题基本明朗了,mac的钥匙串缓存了github的信息,删除掉即可
操作步骤如下:

  • Open “Keychain Access.app” (You can find it in Spotlight or LaunchPad)
  • Select “All items” in Category
  • Search “git”
  • Delete every old & strange items
  • Try to Push again and it just WORKED
Xiuquan

Xiuquan

Xiuquan's Blog

5 日志
5 标签
© 2017 Xiuquan
由 Hexo 强力驱动
主题 - NexT.Mist