知识大全 关于build tool的构想--从ant说起
Posted 知
篇首语:人之相识,贵在相知;人之相知,贵在知心。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 关于build tool的构想--从ant说起相关的知识,希望对你有一定的参考价值。
ant——你要是不会 出门都不好意思跟人打招呼的那个ant 每个人都用过 它是一个build tool 用xml来描述target 用xml来设置每个task的属性 ant的好处我们都体会到了 什么都是xml 而xml地球人都知道 功能强大 从编译java文件到checkin cvs 反正几乎你想得到的功能它都能作 扩展容易 如果你发现某个功能ant没有 自己实现一个Task类就是 一些功能设计得很合理 比如javac和java自动检查时间戳和依赖关系检查等等 但是 用多了 发现缺点也不少 什么都是xml 而xml的语法有些时候显得很繁琐 xml用来描述逻辑异常笨拙 所有的逻辑都只能在java里用Task实现 要做一些跨越不同Task之间的通讯很困难 比如 先读取第一个文件的时间戳 再读取另一个文件中储存的时间戳 再根据两个时间戳之间的距离判断下一步调用哪个task或者target xml的代码重用困难 很难定义一些常用的xml element作为库 然后再不同文件甚至项目中重用 对module的支持有限 仔细想想 其实 需求发展到逻辑重用 模块管理 不同task通讯等 已经离描述数据这个xml最擅长的领域越来越远了 如果把task作为基本的组成元件 那么 上面提出的几点需求 都是关注于对这些基本元件的管理和组合 或者说 glue 到此 口号呼之欲出 那就是 script 很多script 作为一个完整的语言 是做glue的最理想选手 下面谈谈我对一个基于script的built tool的构想 首先 这个build tool仍然需要允许通过java来自定义task 我们定义这样一个接口 java代码: interface Command Object execute(CommandContext ctxt) throws Throwable; 我们计划让所有的task(我们这里叫它们mand)都实现这个接口 CommandContext负责传递一些象log之类的信息 这个execute返回一个Object 这个值作为这个Command的返回值 可以用来和其它的Command通信 我们允许这个函数抛出任何异常 这个framework将会处理这些异常 然后 定义一些基本的Command 比如 ReturnCommand负责直接返回某一个值 java代码: class ReturnCommand implements Command private final Object v; public Object execute(CommandContext ctxt) return v; ReturnCommand(Object v)this v=v; PrintCommand负责打印一句话 java代码: class PrintCommand implements Command private final String msg; public Object execute(CommandContext ctxt) ctxt getLogger() log(msg); return null; PrintCommand(String msg)this msg=msg; FailCommand负责报告错误 java代码: class FailCommand implements Command private final String msg; public Object execute(CommandContext ctxt) throw new CommandException(msg); FailCommand (String msg)this msg=msg; 如此等等 这样的基本元件还有很多 比如file copy javac zip jar等 但是 如果仅仅如此 那么这个工具的能力最多也就和ant一样 我们最需要的 是把不同的mand组合起来的能力 而组合 最常见的 就是顺序执行 java代码: class SeqCommand implements Command private final Command c ; private final Command c ; public Object execute(CommandContext ctxt) c execute(ctxt); return c execute(ctxt); SeqCommand (Command c Command c ) this c = c ; this c = c ; 上面这个简单的Command 就负责按照顺序执行连续的两个mand 除了顺序执行 还有错误处理 我们也许会希望 当某个步骤执行失败时 去执行另外一个动作 为此 我们需要先定义一个接口来描述错误恢复 java代码: interface CommandRecovery Command recover(Throwable th) throws Throwable; 当某个mand失败的时候 这个接口会被调用 实现这个接口 可以有选择地对某一种或者几种错误进行恢复 然后定义具体的错误恢复逻辑 java代码: class RecoveredCommand implements Command private final Command c ; private final CommandRecovery c ; public Object execute(CommandContext ctxt) try return c execute(ctxt); catch(Throwable th) return c recover(th) execute(ctxt); RecoveredCommand (Command c CommandRecovery c ) this c = c ; this c = c ; 有try catch 就有try finally 我们也可以定义一个mand 让它保证某个关键动作必然运行 java代码: class FinallyCommand implements Command private final Command c ; private final Command c ; public Object execute(CommandContext ctxt) try return c execute(ctxt); finally c execute(ctxt); FinallyCommand (Command c Command ) this c = c ; this c = c ; 前面的顺序执行 我们是直接扔掉了前一个mand的返回值 但是有些时候 我们也许希望根据第一个mand的返回值来决定下一步的走向 为此 仿照CommandRecovery接口 定义CommandBinder接口 java代码: interface CommandBinder Command bind(Object v); 然后定义BoundCommand类 java代码: class BoundCommand implements Command private final Command c ; private final CommandBinder c ; public Object execute(CommandContext ctxt) final Object v = return c execute(ctxt); return c bind(v) execute(ctxt); BoundCommand (Command c CommandBinder c ) this c = c ; this c = c ; 先透露一下 这个BoundCommand非常重要 就是它负责在不同的mand间传递信息 基本上的框架搭好了 下面 假设我们用一个类似groovy的脚本来写某个target 我们的目标是先取得当前时间 然后打印出这个时间 然后调用javac 最后在程序结束后 打印程序结束的信息 java代码: new BoundCommand( new GetTimeCommand() new CommandBinder() public Command bind(Object v) final Command c = new PrintCommand( build time is +v); final Command javacc = new JavaCCommand(); final Command done = new PrintCommand( build successful ); return new SeqCommand(c new SeqCommand(javacc done)); ); 上面的代码 先调用GetTimeCommand 取得当前时间 然后把这个实现传递到这个匿名类中去 这个匿名类根据这个时间 创建了下一步的mand c 接下来 它调用两次SeqCommand来表达两次顺序执行 最终 当这个mand被执行的时候 它就会完成我们上面要求的几个步骤 不错 挺好 达到了在步骤间任意传递信息的要求 甚至 我们也可以重用某些mand或者函数 唯一一个问题 这个代码他妈的比xml还恶心! 这还是很简单的情况 如果我们综合顺序 错误处理 分支等等 代码会丑陋得不忍卒睹 看来 不是随便什么script都可以胜任的 那么 让我们先静下心来反过来想想 我们到底希望有什么样的语法呢? 写伪码 应该是这样 java代码: time < getCurrentTime print time javac print success 我们的目标是 用脚本语言把前面繁杂的java代码屏蔽起来 让语法简洁的脚本自动调用上面那些臃肿的代码 幸好 我手头有一个脚本语言可以达到类似的语法 java代码: do time=now $ info print time >> javac classpath= ; fork= ; patibility= ; >> info print build successful 这些do >>等函数其实是用SeqCommand BoundCommand等实现的 只不过表面上看不到了 更加复杂的逻辑 比如包含顺序执行 也包含错误处理的 java代码: auto (info println build done ) $ do time=now $ info println ( build starting at + time) >> do t = readFile file $ do t = readFile file $ let diff = t t ; writeFile file diff end 这段脚本要先读取当前时间 然后打印build start 然后先后从file 和file 读取两个数 然后把这两个数的差额写入file 最后 无论成功与否 打印build done auto函数的意思是 当后面那些东西执行完毕后 无论是否出现exception 都要打印 build done 你如果感兴趣可以试着用java或者groovy写写 看看结果多么可怕 如此 一个完整的build框架就建立起来了 我们只要填空式地给系统加入各种mand实现 一个灵活优美的build tool就出炉了 最后 预告一下 基于这个思想的open source 项目Neptune即将启动 欢迎有志之士参加 你可以参与这个框架核心的搭建(跟我合作) 也可以编写独立的各种Command来丰富框架的功能 cha138/Article/program/Java/ky/201311/28218相关参考
知识大全 关于build tool的构想 从Ant说起[5]
关于buildtool的构想从Ant说起[5] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
知识大全 关于build tool的构想 从Ant说起[4]
关于buildtool的构想从Ant说起[4] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
知识大全 关于build tool的构想 从Ant说起[3]
关于buildtool的构想从Ant说起[3] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
知识大全 关于build tool的构想 从Ant说起[2]
关于buildtool的构想从Ant说起[2] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
知识大全 关于build tool的构想 从Ant说起[11]
关于buildtool的构想从Ant说起[11] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&n
知识大全 关于build tool的构想 从Ant说起[10]
关于buildtool的构想从Ant说起[10] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&n
知识大全 关于build tool的构想 从Ant说起[9]
关于buildtool的构想从Ant说起[9] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
知识大全 关于build tool的构想 从Ant说起[8]
关于buildtool的构想从Ant说起[8] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb
知识大全 关于build tool的构想 从Ant说起[7]
关于buildtool的构想从Ant说起[7] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb