自己用nant 的过程中发现的一些几乎有用的小片断, 不好意思学人家叫cookbook, 还没到那个规模
基于NAnt 0.85 (Build 0.85.2478.0; release; 2006-10-14)
1. 取当前日期时间: 内置task: tstamp
time stamp的缩写
<tstamp property="curr_time" pattern="yyyy-MM-dd HH:mm:ss" verbose="false"/> <echo message="${curr_time}" />
|
[tstamp] 2007年10月24日 11:25:16.
[echo] 2007-10-24 11:25:16
[tstamp] 那一行有时候会变得很讨厌, 但没办法关闭, 你也许已经看到我企图用verbose="false"来关闭它, 但没用.
pattern中的大小写是敏感的, 我想上面给出的格式在绝大多数情况下就都足够用了, 精确到了秒.
对于只是想提供日期时间信息, 但不在乎格式, 又不想记这些pattern怎么写的人, 可以简单地用
<tstamp /> <echo message="${ tstamp.now } | ${tstamp.date} | ${tstamp.time}" />
|
但是, 它的输出往往对中国人是不友好的, 我们不习惯 "月/日/年"这样的表达法, 面对 03/05/2007 总是会怀疑究竟是3月5号, 还是5月3号. 所以, 我对同胞们的建议是: 不要用这三个变量的值显示给不管是你自己还是你的同事看.
每一次执行一个tstamp 任务, 它会设置上面的3个变量, 注意这三个变量并非是每次取用的时候就自动是当前的日期/时间值, 必需对它进行设置. 这不是.NET中的 DateTime.Now 属性.
个人认为在启动一个nant任务时默认地给这三个变量赋值是比较合适的做法, 但目前的nant 不是这样做的, 从未执行一次
任务就去使用这三个变量会导致变量未赋值的错误:
Expression: ${tstamp.now} | ${tstamp.date} | ${tstamp.time}
^^^^^^^^^^
Property 'tstamp.now' has not been set.
|
注意并非为了设置这三个变量就得运行一个
这样的最简形式, 设置这三个变量的值是只要运行该任务就一定会有的副作用.
2. 显示信息: echo 内置任务
nant中的echo 就是 C中的printf, 它几乎是每个人都会用/都想用, 甚至也是用的最多的调试手段. 最简单的形式:
<echo message="Hello, world"/>
|
既使它如此简单, 我相信下面的内容还是绝对你一看:
2.1 在XML的属性中换行:
<echo message="Hello
world"/>
|
是XML的Entity, 十进制, 表示换行, 就是你在C字符串中的\n
2.2 输出大块文本
<echo>
Hello, world
The time is, ${tstamp.now}
]]>
|
是XML有意定义的怪兽, 目的就是尽可能的奇怪, 以致于你基本不可能在有意义的文本中用到. 它里面可以放大块大块的内容, 而且可以含有 <> 这样的在普通XML文本和XML属性中被禁止使用的值.
但是, 我认为nant还是对XML的这种机制进行了有意的违背: 它允许使用变量内插, 就是上面的${tstamp.now}, 类似于bash 中的 <
...
END
和perl中双引号中允许内插变量值一样. 这个十分方便, 否则你就得不停地在
2.3 用if 控制是否输出
不管是程序代码还是 nant脚本, 如果有一次你需要这样的输出来帮助调试, 那么很大的机会你以后还会要, 所以即使调试完之后也不要把printf/echo 删除, 而是把它留在代码里, 用一个开关随时切换.
C/C++可以用
#if 0
#endif
C#必需用 #if false, 它不支持#if 0
对于几乎所有的nant 任务, 都可以指定一个if 属性来通过条件控制是否执行, 简单地禁用需要这样:
if="false"
2.4 用 file="filename.txt" 和 append="true" 控制向文件写入
写入的内容不再是到标准输出, 而是重定向到了指定的文件.
3. 执行外部命令: exec 内置任务
执行外部命令非常常用, 即使是nant内置了cvs/mail这样的任务, 但并不是每个任务都能很好地工作, 所以我实际上是用cvs.exe 命令来取代码, 用perl脚本来发邮件:
<exec program="nant.exe"
commandline="-buildfile:Build.Build -l:${log_file} ${build_target}"
workingdir="${build_dir}/MyProject/src" output="output.txt"
failonerror="false" resultproperty="build_result" />
|
program 是必需的, 注意只在这里写可执行文件名, 不要写参数, nant会认为整个program属性的内容都是
可执行文件的名字, 不必是绝对路径, 只要在%PATH%变量中可以找到即可, 目录名/文件名中也可以含有空格.
commandline也几乎是必需的, 所有的参数都一古脑写在这里, 不要用什么单独的arg标签.
workingdir 有时候对命令的正确执行至关重要, 比如上面的cvs命令, 它就关乎着取出的代码放在哪个目录下.
failonerror 和 resultproperty 两个往往一起使用, resultproperty 的返回值就是C里面exit( code ); 的参数值. 代表进程的退出状态, 一般的约定是0为正常, 其它值有错误.
注意接下来取用 resultproperty 值的时候它却被当作是一个字符串, 因此你不能用这样的条件来进行判断:
if = "${ resultproperty == 0}"
而必需是
if = "${ resultproperty == '0'}"
output属性把命令执行的结果同时存为指定的文件, 注意同时标准输出上还是会显示命令的输出, 包括标准输出和标准错误输出, 没有简单的办法来禁止向标准输出写东西, 下面是一个可行但不那么优雅的方案
这个命令行不通过 output来指定输出文件, 而是通过 commandline, 在里面指定 > tmp.txt进行重定向, 注意需要用> 来代替>符号, 这是XML!
也许你注意到了, echo 用file表示输出文件, 而这里用 output, 是的, 我也讨厌这样的不一致.
4. 显示所有可调用的target
不象makefile, 你没有简单的办法列出所有可以作为目标的名称,
nant -f:file.build -projecthelp
会显示所有的target
5. 退出脚本执行: fail内置任务
有时候为了调试时跳过一段耗时太长的脚本, 你希望有一个C语言中exit(1)一样的功能, 在nant中是 fail内置任务, 因为nant默认的规则是碰到错误就退出, 所以你强制一个错误发生就相当于让它退出. 不同的是你无法指定一个退出码, fail一定会被外部的程序视为错误, nant返回时 %errorlevel%的值是1
6. property 值是全局变量
注意所有调用的property 属性都是全局性质的, 不管你是通过 call, 还是因为 依赖关系调用的, 一经设置, 一直生效.
7. 判断存在性
if="${property::exists('var_name')}"
if="${file::exists('filename')}"
if="${directory::exists('dirname')}"
这个exists 名字起的还算统一
8. 如果涉及路径名/文件名, 一概用绝对路径.
跟shell脚本的惯例一样, 这样参避免很多问题.
9. 如果涉及property 这样的可变值, 在脚本头部, 尽可能集中地一次性设置好.
这样你改起来方便. 也符合软件工程里把变化的部分和不变的部分分开管理的原则.
阅读(1036) | 评论(0) | 转发(0) |