Fossil 的分支处理

Oct 01, 2014 10:28:01 AM

MemMaster 的开发是用 Fossil 做版本管理的。最近需要分支开发,于是研究了一下 Fossil 的分支处理。(但是在研究过程中对我的仓库造成了永久性不可恢复的损害……)

Be careful!fossil 有个不知该说好还是坏的设计,commit 之后就永远不能再修改了……不过可以有限地补救一下,只不过补救其实是个新的 commit。

原理

官网 wiki。我来总结一下。fossil 使用签入标志(check-in tag)区分分支。每个分支的最新签入被称为开叶(open leaf),即允许有 children 的 leaf。如果在这个开叶上新建分支,则这个开叶被称作分支点(branch point)。如果两个人同时对某一个签入作出改动,其中一个人首先commit,那么原来的开叶标记会移动到新的签入上,后来的人将无法推送修改,那么此时就应该弄个分支,然后再回到原分支合并回去。与开叶相对,有闭叶(closed leaf),最后一个签入是闭叶的分支将永久封存,不得进一步修改。

新建分支

fossil 要求创建分支时提供 basis,即从哪个签入分支。虽然看上去好像nb了些,实际上徒增麻烦而已。

# fossil branch new [分支名] [基础]
fossil branch new testing trunk
fossil branch new testing [commit编号]

切换分支

fossil 不支持就地切换,你得再 open 一次。

cd ..
mkdir branch-testing
cd branch-testing
fossil open /path/to/repo.fossil testing

查看当前分支

fossil branch ls

当前分支的名字前面会有一个 *。

删除分支

删除分支?开玩笑呢。你只能把一个分支关闭,相当于删除了。这个很简单,在 timeline 的最后一个 leaf 那里,点 edit,然后 close 掉就行了。当然,close之后,branch ls、web 界面里面是没有显示的。

Tags: fossil
评论(0) 阅读(26)

Tcl 现代方法:TclHttpd 入门

Sep 30, 2014 04:46:08 PM

TclHttpd 是 Tcl 界人尽皆知的有名软件,功能强大,易于使用。在其原作者不再维护之后,Cliff 和 Sean 于最近接手维护,使之支持最新的 8.6。

可通过以下命令获得 TclHttpd:

fossil clone http://core.tcl.tk/tclhttpd/ /path/to/tclhttpd.fossil
mkdir /path/to/tclhttpd; cd /path/to/tclhttpd
fossil open /path/to/tclhttpd.fossil

恭喜!你已经获得了一个能用的 TclHttpd。

现在我们先试试:

tclsh bin/httpd.tcl -debug 1

观察控制台输出可以得知一些信息,如 debug、webmaster 用户密码等。访问 localhost:8015 可以看到 TclHttpd 默认的页面。

现在就能写个 hello world 了:

Direct_Url /hello Hello
proc Hello/world {} {
   return "<b>Hello, World!</b>"
}

存盘到 example/hello.tcl 下。然后执行命令:

tclsh bin/httpd.tcl -library example -debug 1

再访问 localhost:8015/hello/world 就能看到粗体的问候了!

Tags: tcl tcl 现代方法 tclhttpd
评论(0) 阅读(58)

Tcl 现代方法:tailcall

Sep 21, 2014 09:30:49 PM

Tailcall 是 Tcl 8.6 引入的新功能。功能如其名,本来是用来实现尾调用的。

proc factorial {n {accum 1}} {
    if {$n < 2} {
        return $accum
    }
    tailcall factorial [expr {$n - 1}] [expr {$accum * $n}]
}

tailcall 有个实现细节:替换掉当前的栈。于是带来了一些有趣的妙用。

proc min {a b} {
    if {$a > $b} {
        tailcall max $b $a
    }
    return $a
}

这个 min 函数故意绕弯,对于最坏的情况会导致两个 if 检查,但是对于一些比较复杂的函数,就让人麻烦了。比如说

# 
# Make sure b is greater than a!
# 
proc ComplexCalculation {a b} {
    if {$a > $b} {
        tailcall ComplexCalculation $b $a
    }
    # Much
    # Code
    # Omitted
}

尽管我们在文档里面写了要求 b 大于 a,但是有的情况下我们不知道哪个大于哪个呀!而且有的时候脑袋一懵写反了就糟糕了。在没有 tailcall 之前,我们必须得自己判断哪个大于哪个,麻烦死了,这点工作还是隐藏起来好了(从代码重用的角度看也应该这么做)。于是加上简简单单三行代码,就可以轻松省下许许多多的判断。

另外一个用处,被莫名其妙地用来实现 do ... while 控制结构……(出处,这段小小的代码也被我用到了记忆大师里面。)

proc do {code while cond} {
    tailcall try $code\n[list $while $cond $code]
}

因为 tailcall 的一个奇妙的实现细节,我们就多了这么多乐趣!我曾经在 Tcl Chatroom 里面「抱怨」说 tailcall 不应该叫 tailcall,应该叫 replaceCurrentStackFrame。这时候有个人说,尾调用 tailcall 的意思就是在一个栈的尾部调用嘛!恍然大悟。

Tags: tcl tcl 现代方法
评论(0) 阅读(102)

Tcl 现代方法:eval 方法大全

Sep 21, 2014 08:40:12 PM

#include <tcl.h>

/**
 * puts [set a [expr {20 * 30}]
 */
void EvalString(Tcl_Interp *interp) {
    Tcl_Obj *result;
    char script[] = "set a [expr {20 * 30}]";
    
    if (Tcl_Eval(interp, script) != TCL_OK) {
        fprintf(stderr, "Error was: %s\n", Tcl_GetStringResult(interp));
        return;
    }
    result = Tcl_GetObjResult(interp);
    printf("%s\n", Tcl_GetStringFromObj(result, NULL));
}

/**
 * puts [set a [expr {30 * 30}]]
 */
void EvalStringObj(Tcl_Interp *interp) {
    Tcl_Obj *script;
    Tcl_Obj *result;
    
    script = Tcl_NewStringObj("set a [expr {30 * 30}]", -1);
    Tcl_IncrRefCount(script);
    Tcl_EvalObjEx(interp, script, 0);
    result = Tcl_GetObjResult(interp);
    printf("%s\n", Tcl_GetStringFromObj(result, NULL));
}

/**
 * puts {hello world}
 */
void EvalListObj(Tcl_Interp *interp) {
    Tcl_Obj *cmd;
    cmd = Tcl_NewObj();
    Tcl_ListObjAppendElement(interp, cmd, Tcl_NewStringObj("puts", -1));
    Tcl_ListObjAppendElement(interp, cmd, Tcl_NewStringObj("hello world", -1));
    Tcl_IncrRefCount(cmd);
    Tcl_EvalObjEx(interp, cmd, 0);
    Tcl_DecrRefCount(cmd);
}

/**
 * puts [set a 32]
 */
void Eval(Tcl_Interp *interp) {
    int i;
    Tcl_Obj *scriptArr[3];
    Tcl_Obj *resultObj;
    int result;
    
    scriptArr[0] = Tcl_NewStringObj("set", 3);
    scriptArr[1] = Tcl_NewStringObj("a", 1);
    scriptArr[2] = Tcl_NewIntObj(32);
    for (i = 0; i < 3; ++i) {
        Tcl_IncrRefCount(scriptArr[i]);
    }
    Tcl_EvalObjv(interp, 3, scriptArr, 0);
    for (i = 0; i < 3; ++i) {
        Tcl_DecrRefCount(scriptArr[i]);
    }
    resultObj = Tcl_GetObjResult(interp);
    Tcl_IncrRefCount(resultObj);
    Tcl_GetIntFromObj(interp, resultObj, &result);
    Tcl_DecrRefCount(resultObj);
    printf("%d\n", result);
}

int main(int argc, char *argv[]) {
    Tcl_Interp *interp;
    
    interp = Tcl_CreateInterp();
    EvalString(interp);
    EvalStringObj(interp);
    EvalListObj(interp);
    Eval(interp);
    Tcl_DeleteInterp(interp);
    return 0;
}

Tags: tcl tcl 现代方法
评论(0) 阅读(89)

新设计的字符串匹配

Aug 29, 2014 04:16:03 PM

正则太麻烦了,我又太笨,学不会,就自己随便设计一个。当然也只是随便设计而已。

'' 括起来的字符串表示是独立的单词,如输入 'hello' 则不会和 helloworld 匹配

"" 括起来的字符串表示可与其他,如输入 "hello" 则会与 helloworld 匹配

在一个匹配节中,紧挨在前面的数字是重复次数,空表示一次,多次可用空格分开, - 表示连续,如 (digit) 表示匹配一个数字,2(number) 表示匹配两个数字(如 10, 99,但不匹配 1、100),*(digit) 匹配一以上位数字,^(digital) 匹配零以上位数字。

(digit 接受的数字):匹配一个数字([0,9]),不独立。也可以在这里使用连续的列表。如 (digit 100-200) 表示匹配在 [100,200] 中的一切整数,此时无视“一个数字”限制。

(standalone):强制独立,即使写成 (standalone "str") 也视作 'str';写作 (standalone (digit)) 则匹配一个独立的数字,如匹配 1 不匹配 12,写作 2(standalone (digit)) 或 *(standalone (digit)) 则匹配 “1 2” “2 4” 等有间隔的数字。

(join 一系列东西 中间插入的东西):匹配如同 join 返回的结果一样的文本,如 (join *(digit) ".") 匹配 1.2.3.4.100 和 100.300.600.0.1 等。

(or 选择一 选择二 选择三):使用多种方式匹配,若相同一段文本在三种选择中都匹配,则返回匹配长度最长的一种。

(have 名字 匹配格式):自定义匹配方法。如 (have number (or (digit 0) "") "." *(digit)),以后就可以使用 (number) 来匹配

(match 起始 结束):匹配有开始和结束的一段文本。匹配最长的文本。如 "{{ a } b} {c}" 则匹配得到 "{{ a } b}" 和 "{c}",{ a } 并不放出。

(match 起始结束):如双引号,本身就可以结束自己。

(line 位置 匹配节):位置可以是 start,end,middle。

 

一个 () 代表一个匹配节,是一个逻辑单位,[] 作用与 () 相同,只是为了避免嵌套过多难于阅读。

 

上面这些看着有点像是文本处理的 DSL 了,举些例子:

# IPv4 地址
(join 4(digital 0-255) ".")

# 浮点数(要求有小数点)
(or [^(digital) "." ^(digital)]
    [*(digital) "." ^(digital)]
    [^(digital) "." *(digital)])

# 电话号码(3或4位区号+横线(连接在一起或没有连接在一起)+7或8位电话)
3,4(digital) (or "-" '-') 7,8(digital)

# 随便什么。。
(match 'for' 'next')

# 匹配 ⑨ 个独立的数字
(have float (or [^(digital) "." ^(digital)]
                [*(digital) "." ^(digital)]
                [^(digital) "." *(digital)]))
(have integer ^(digital))
(have number (or (integer) (float)))
9(standalone (number))

Tags: 正则表达式 RegEx
评论(2) 阅读(228)

Tcl 实现伪闭包

Aug 28, 2014 10:51:00 PM

proc lambda {vars args body} {
    set exvars [lmap var $vars {
        upvar $var localvar
        list $var $localvar
    }]
    lappend args {*}$exvars
    list apply [list $args $body]
}

简单地用 apply 实现一个“伪闭包”。其中 {*} 需要 Tcl 8.5,[lmap] 需要 8.6。

所谓“伪”是因为这个函数没法真正地持有变量引用,只能复制一下。有点像是缩水版的 C++ 闭包frown。虽说只是复制,但还是十分好用,因为 Tcl 在核心层面的“复制”使用的是引用计数,而且若原函数退出,也不会影响到匿名函数里面的变量,毕竟 Tcl 是没有垃圾收集的,这样做凑合能算不错吧。

有个比较遗憾的限制是,因为我比较懒,用“可选参数”实现了变量复制,所以如果参数列表有 args 且使用了外部变量,就会退化到普通的变量(正如 lambda 自身的 args)。

这个函数基本用法是这样的:

set x 100
{*}[lambda x {a b} {
    puts "x = $x\na=$a\nb=$b"
}] 10 20

自然,你也可以给 lambda 返回的“闭包”一个名字:

set x 100
set closure [lambda x {a b} {
    puts "x = $x\na=$a\nb=$b"
}]
{*}$closure 10 20

实际上,这玩意在 Tk 上最好用:

proc foo {} {
    set msg "使用 lambda 辅助函数十分方便吧!"
    ttk::button .b -text 点我 -command [lambda msg {} {
        tk_messageBox -message $msg
    }]
    pack .b
}
foo

一般情况下,Tk 直接这样写是不行的,因为 -command 是在全局命名空间里执行的:

proc foo {} {
    set msg "这是不行的!"
    ttk::button .b -text 点我 -command {
        tk_messageBox -message $msg
    }
    pack .b
}
foo

会报错找不到 msg 变量。

如果你比较熟悉 Tcl,可能想问为什么不用 subst,像下面这样:

proc foo {} {
    set msg "hello tcl!"
    ttk::button .b -text 点我 -command [subst -nocommands {
        tk_messageBox -message $msg
    }]
    pack .b
}
foo

我开始也以为可以,但遗憾的是,不行。因为 Tk 使用 eval 处理 command,在上面的例子中,eval 会把原来好好的命令曲解成这样:

tk_messageBox -message hello tcl!
# 也就是
tk_messageBox -message {*}"hello tcl!"

这是因为 eval 使用了 concat,而 concat 会把列表展开一层,正如 {*} 一样:

concat {{1 2} 3} 4
# → {1 2} 3 4

eval 的“展开”特性在少数情况下有用,大部分情况下 {*} 就可以替代 eval,在此不赘述。

Tags: tcl
评论(0) 阅读(190)

Common Lisp 的無限可能——GTK+ 3 與 CL 的快速圖形程序開發及簡單的 CL 介紹

Feb 14, 2013 07:08:20 PM

章甲、虎頭

大家也許已經不止一次從 Lisp 的狂熱愛好者那裏聽說了「Lisp 真是世界第一語言」「Lisp 最 NB」之類的話。俺不想說那些沒用的玩意,今天就是上來發個小小的示例,GTK+3 和 Common Lisp 在一起是什麼模樣?

Tags: gtk gtk3 lisp common-lisp
评论(0) 阅读(3165)

Fedora 使用 Broadcom 43xx 官方驱动

Jul 23, 2012 04:51:06 PM

我是一个大骗子,因为我又回来了。。哦不,准确说是被逼无奈啊。详情我就不说了,太伤心了。

首先下载 bcm Linux-STA 驱动。

make
sudo make install
insmod wl.ko
depmod -a
modprobe wl

好了

评论(2) 阅读(1294)

GObject 好文搜集

Aug 17, 2011 03:57:37 PM

我个人并没有全看过,看过也不一定完全懂,有问题请去相关页面留言问原作者。

以下是 is-Programmer.com 大牛写的

当你把以下文章完全看透,你就可以说你已经会 GObject 了(不仅仅是入门)。

Tiger Soldier 写的:

《探索 GObject(1):封装》

有点可惜的是第二篇无限延长了。。 话说这是 is-Programmer.com 上第一篇有关 GObject 的文章。

Tiger Soldier 是 OSD Lyrics 的作者。

pingf 写的:

《恶心的GObject[Part I][v0.1]》

文题虽稍显不雅,但内容很好,甚至是联系源代码的。有点可惜的是第二篇还是没出来。

pingf 是 OOC-GCC 的作者。

过眼云烟写的:

《对g_signal_new()参数的解释》

《使用 Boxed Type 机制包装 C 语言结构体

《在 GObject 中使用接口》

Garfileo 的 GObject 系列文章,因为他自己已经给出了目录,我就不多嘴了:

《GObject 学习笔记汇总》

有点可惜的是没有 PDF 版离线阅读……

Garfileo 是尚未面世的 Cikada 的作者。

站外链接

GNOME 官方的 GObject 手册。别人都说很老了,也很晦涩, Garfileo 说你能完全看懂里面的 Concepts 的话,就不用看他的文了。

Wikipedia 的 GObject 介绍

GObject对象系统》。很简单的入门文,不过似乎并不完全参照以上文所述的方法。

以下是 Ubuntu Tweak 作者 TualatriX 所翻译的官方手册:

GObject参考手册:序

1、概念:GObject 的开发背景

2、GLib 动态类型系统

3、GLib 的一些规范

4、不可实例和不可类化的类型

5、可实例化的类型:对象

6、不可实例的类型:接口

7、基类:GObject

8、GObject的内存管理

9、GObject的对象属性

10、GObject的消息系统:Closure(这个是叫闭包吧?)

开始学习吧!

Tags: GObject
评论(4) 阅读(2881)

bsdman —— linux下看freebsd的手册页

Aug 15, 2011 11:55:46 AM

用不到50行shell搞定了原来用300行C还没搞定的东西。

现在的版本是 0.2.1(0.2实现的依云需要的功能,结果忘了改下面的代码,于是又有了0.2.1),功能如下:

  • 智能判断分页器(more或你自己定义的,需要设置 PAGER 环境变量)
  • 无垃圾文件
  • 浏览 FreeBSD 的手册页

用法很简单

bsdman [要man的东西] [节]

代码很短,要看就自己看吧。。

仓库

*这是我在arch下第一个写的无意义的东西。

Tags: linux shell FREEBSD bsd bsdman
评论(0) 阅读(1671)