7C00.ME/houmu 2015-08-18

Bocker源码赏析:技巧篇

Bocker源码中由几处技巧非常巧妙,颇值得鉴赏一番。

I. 帮助

Bocker help功能之实现,实在是妙!普通程序员偷懒一点,用echo prog [cmd1|cmd2]应付一下,勤快点的会把详细点的文本一行行echo出来。bocker没有偷懒,却也实现了一个比较详细的help,当键入bocker help的时候,终端里面会哗啦啦列出一长段说明。但是,这个功能对应的函数只有一行sed -n "s/^.*#HELP\\s//p;" < "$1" | sed "s/\\\\n/\n\t/g;s/$/\n/;s!BOCKER!${1/!/\\!}!g"

实现原理其实非常简单:bocker中每个功能对应一个函数,这些函数在声明的时候都遵循这样的格式:

function bocker_init() { #HELP Create an image from a directory:\nBOCKER init <directory>
# ...do sth.
}

每个函数声明后面都带一行说明这个函数功能的注释,注意统一以#HELP开头,用\n分割功能和用法。这样当使用docker help的时候,使用sed命令,从bocker脚本文件本身(这里使用了$0的小技巧)把那些#help注释提取出来,再整理一下,大功告成,excited!

这个技巧甚是厉害,一来,实现了一个不错的help功能;二来,控制了代码行数;三来,“注释即文档”,易于维护。

II. BOCKER_OPTION

处理命令行选项是一个很常见的任务,Python标准库里面就有getopt、optparse、argparse这么多面向这一任务的库,可见此事平凡却不容易。Bocker只用一行代码,实现了一个可以供以后借鉴的模式:

[[ $# -gt 0 ]] && while [ "${1:0:2}" == '--' ]; do OPTION=${1:2}; [[ $OPTION =~ = ]] && declare "BOCKER_${OPTION/=*/}=${OPTION/*=/}" || declare "BOCKER_${OPTION}=x"; shift; done

这行代码有点长,有点不太符合一般的编码规范,但是其设计还是不错的。这一行代码深深地体现出了作者的编程功力,他对bash脚本字符串处理已经炉火纯青了!下文还会见识到。

III. 随机字符串

Bocker中三处随机字符串生成,用了两种方法:1,uuidgen,在bocker_pull函数中出现,为临时目录分配一个不会重复的路径,其实是还可以用mktemp;2,shuf -i 42002-42254,在bocker_runbocker_init函数中出现,为容器和image分配一个唯一的id,分别前缀ps_img_

当然如果仅仅是这样,倒也不值得单独一提,直到看到 cmd="${@:2}" && ip="$(echo "${uuid: -3}" | sed 's/0//g')" && mac="${uuid: -3:1}:${uuid: -2}", 才忽然发现其中暗藏玄机。随机数的取值范围不是随便定的,末尾三位数正好在一个C类IP的子网地址范围内,还兼顾了mac地址(这行代码里面又显露了作者娴熟的Bash字符串处理技巧);起始的‘42’则是the answer to life, the universe, and everything

Bocker代码像一块精致的糕点,分量不大,但是回味无穷。