β

开发mercurial(hg)扩展

宇义's blog 318 阅读

最近把静态项目管理工具中的“中央服务器自动编译”功能从bash改写成了python,因为静态项目管理工具就是用python写的,理论上编译速度会更快,改写后以前经常遇到的超时问题已经很久没有遇到了。

而作为中央服务器最重要的代码版本控制工具mercurial,同样也是python写的,使得两者有了非常自然的结合,干脆搜索了一些资料,将自动合并脚本改写成了一个mercurial的扩展,让使用者可以更统一的对编译过程进行配置。

整个扩展的开发过程还算顺利,有一片非常详细的开发文档(英文) http://mercurial.selenic.com/wiki/WritingExtensions ,我根据这篇文档进行了简单的总结,希望对开发mercurial扩展的朋友有所帮助。

Mercurial扩展一般都编写成一个简单的python模块。大一些扩展可以拆分成多个模块成为一个package。在模块中有几个特殊成员,mercurial就是通过这些特殊成员为hg命令扩展功能的。

1 cmdtable

通过为python模块提供dict格式的cmdtable变量,可以为hg增加子命令。

cmdtable = {
    # "子命令名称": (调用函数, 命令选项, 帮助信息)
    "print-parents": (printparents,
                     [('s', 'short', None, 'print short form'),
                      ('l', 'long', None, 'print long form')],
                     "hg print-parents [options] node")
}

调用函数会依次传递 ui, repo, 命令选项参数。选项名中的减号在转换成参数名称时会被替换成下划线。

2 ui、repo参数

ui是hg命令行用于与用户进行交互的实用对象,也可用于获取当前版本库的配置信息;

ui.write(*msg)

ui.prompt(msg, default=”y”)

ui.wran(*msg)

ui.setconfig(‘片段名’, ‘字段名’, ‘值’)

# 值如果是一个hook,可直接传递hook函数

ui.setconfig(‘hooks’, ‘pre-update.default’, myhook)

ui.config(‘片段名’, ‘字段名’, ‘默认值’)

repo则是一个版本库的实例:

repo.root #版本库路径

repo[node] # 可获取某个版本的节点,比如 repo['tip']

repo.ui # 此repo正在使用的ui对象

创建获取一个repo对象可使用:

mercurial.hg.repository(mercurial.ui.ui(), repo_path)

3 事件函数

可通过定义 uisetup(ui)、reposetup(ui, repo)、extsetup(ui) 三种函数分别捕获ui、repo、和扩展本身的创建完毕的过程。

4 定义hook

如果你的扩展需要在某些命令被执行时触发的话,可通过设置用户的配置,为其添加hook的方式进行:

def preupdatehook(ui, repo, **kwargs):
    print("Pre-update hook triggered")
def updatehook(ui, repo, **kwargs):
    print("Update hook triggered")
def uisetup(ui):
    ui.setconfig("hooks", "pre-update.myextension", preupdatehook)
def reposetup(ui, repo):
    ui.setconfig("hooks", "update.myextension", updatehook)

5 包装命令

可通过 wrapcommand 为hg的已有命令进行处理,包括增加选项,改变默认行为等。

def pullwrapper(orig, *args, **kwargs):
result = orig(*args, **kwargs) # 执行默认的处理
if kwargs['depts']:
# your code here
return result

entry = mercurial.extensions.wrapcommand(mercurial.commands.table, ‘pull’, pullwrapper) # 获取 pull 命令的配置

entry[1].append((‘D’, ‘depts’, None, _(‘pull dependencies’))) # 为 pull 命令增加一个 -D / –depts 选项

# 经过测试,update似乎无法使用此方法添加选项,调用时会提示参数错误,不知道是不是hg的bug

6 已知问题

mercurial修改了python的import的默认行为,使其成为了“懒加载”,只有在某个模块的成员被调用时,才会真正的将此模块进行加载。这种处理方式可能导致你的扩展中的某个第三方模块出现问题。好在这个行为是可以关闭的:

mercurial.demandimport.disable()

作者:宇义's blog
原文地址:开发mercurial(hg)扩展, 感谢原作者分享。

发表评论