<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" gd:etag="W/&quot;C0YCQH45fCp7ImA9WhRWEEU.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842</id><updated>2011-12-28T22:06:01.024+08:00</updated><category term="rmake" /><category term="linux" /><category term="barcamp" /><category term="telepathy" /><category term="packaging" /><category term="package" /><category term="web" /><category term="programming" /><category term="politics" /><category term="gnome-shell" /><category term="community" /><category term="scim" /><category term="systemd" /><category term="language" /><category term="django" /><category term="book" /><category term="evolution" /><category term="c" /><category term="life" /><category term="gnome" /><category term="firefox" /><category term="foresight" /><category term="sudoku" /><category term="GSoC" /><category term="git" /><category term="beihang" /><category term="python" /><category term="shell" /><category term="conary" /><category term="gnome developer kit" /><category term="kernel" /><category term="windows" /><category term="qemu" /><category term="vim" /><category term="chinese" /><title>Jesse's Blog</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.zhangsen.org/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>90</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/zhangsen-blog" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="zhangsen-blog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;C0YDRnw5fip7ImA9WhRRF0k.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-7924585629015608568</id><published>2011-11-30T18:47:00.001+08:00</published><updated>2011-12-01T20:06:17.226+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-01T20:06:17.226+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="language" /><title>languages</title><content type="html">(按：写完后，发现此文甚水，而且处处强词夺理。不过有几个地方应该还有点道理，而且我这种人写出文章来就不舍得扔了，所以依然发表。权当博君一笑吧。)&lt;br /&gt;
&lt;br /&gt;
用汉语，英语和法语表达“我是歌手”：&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;img border="0" src="http://2.bp.blogspot.com/-0CdnJbKJgHw/TtY5aqkoiyI/AAAAAAAAASw/UYuvfQ1ClHc/s1600/language-comparison.png" /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;br /&gt;
可以看到汉语和英语的语法都相对简单，而汉语更简单一点。上面的汉语例句中，系动词“是”和表语“歌手“没有任何变化，而英语还是保留了一些时态和语态的规则，虽然英语也在变得越来越简单 (趋向于所谓分析语)。&lt;br /&gt;
&lt;br /&gt;
所以说，在语法和语音层面上 (暂且抛开文字不谈)，汉语是一门很简单的语言。那些操着半吊子汉语，还在泡中国姑娘的老外，实在是懒 (抑或是幸运?)。&lt;br /&gt;
&lt;br /&gt;
法国人一向以自己的语言自豪，而法语确实有一种独特的韵味。即使一句普通的话，比如 à la prochaine fois，意思明确，又不失美感。作为对比，英语怎样呢？Till the next time? 意思接近，但是显得别扭，做作；Goodbye, 又偏离原意了。汉语呢，“拜拜”估计是英语中来的，意思同样不准确，放在这也不应景；“再见”，倒正是这个意思，但是在大量使用下，已经丢掉了字面上的本意；不过汉语中确实有个好的，“回见”，虽然略显北京腔。&lt;br /&gt;
&lt;br /&gt;
再看这个例子，传说路易十五曾经这样预言，“在我之后，洪水将至”。法语原文是 &lt;span lang="fr"&gt;Après nous, le déluge。英语翻译是 &lt;/span&gt;After me, the flood。&lt;br /&gt;
&lt;br /&gt;
法语依然韵味十足，而我们也能发现英语的一个特点，就是直接，practical。汉语呢，对一个事情往往能有多种表述。语法的简单意味着更少的拘束，更加灵活。&lt;br /&gt;
&lt;br /&gt;
比如这句话 (来自亦舒的一句诗)，彼之熊掌，我之砒霜；或者“彼之琼瑶，我之砒霜”；“彼之蜜糖，我之砒霜”；每一种表述，虽然含义相同，但都带有独特的风味。同样的意思，英语中的经典表述是 One man's food is another's poison. 好直接... 而且即使把 food/poison 换成别的组合，也不会给人不一样的感觉。那法语呢，有伏尔泰的一句话，Le malheur des uns fait le bonheur des autres. 还是法语的特点，表意明确，没有二义，韵味也不失。&lt;br /&gt;
&lt;br /&gt;
汉语中，字词本身不会有语态时态的变化，而且字词的数量比较小 (相对拼音文字的单词)，一句话的意思全靠句子结构、遣词造句来表达 (所谓分析语)，所以句子往往很灵活，说一件事有很多说法，可以高贵，可以卑微，可以直接，可以含蓄。与之相对，英语中单词的意思一般比较单一，句子很少有附加或曲折的含义。&lt;br /&gt;
&lt;br /&gt;
所以说汉语既简单，又灵活，是一种与法语不一样的博大精深。英语则完全是一种实用派的语言，有事说事，直截了当。这些语言都有自己的特点，很难说是优点，也很难说是缺点。&lt;br /&gt;
&lt;br /&gt;
说起法语和法国人的自豪，有一个很重要的原因是法兰西学院，几百年来一直是法语的权威机构，主导法语的发展方向，保持着法语的纯正性。汉语和英语都没有类似的机构，所以两种语言发展的更自由，变化也更大。这一点同样无法评判是好是坏。&lt;br /&gt;
&lt;br /&gt;
当然，很难想象如果有一个“中华学术院”会是个什么样子。极有可能，就沦为作协一样的傀儡了。&lt;br /&gt;
&lt;br /&gt;
而且抛开文化不谈，单从语言特点上看，汉语更容易被操控。乌托邦文学中描述的极权政府经常会有对语言的控制，无论是一九八四中的“新话”，还是电影 V for Vendetta 中的 “I remember how the meaning of words began to change. ... I remember how "different" became dangerous.” 但是对拼音文字来说，这并不是那么的致命。因为他们有大量的词汇可以使用，更可以创造新词。但是汉语就不同，汉字和词语的数量都不大，很难造出新字或新词。如果一个字或词被操纵了，对整个语言的影响会很大。或者说，我们要想挤掉语言中的狼奶，会更难。&lt;br /&gt;
&lt;br /&gt;
英语国家的女权运动中，对语言的修改是一种很重要的表现形式。而汉语中很难做类似的语言游戏。不只是女权运动，汉语就像这个国家一样，转身总是很艰难。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-7924585629015608568?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/KQjB0HGLJTM" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/7924585629015608568?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/7924585629015608568?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/11/languages.html" title="languages" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-0CdnJbKJgHw/TtY5aqkoiyI/AAAAAAAAASw/UYuvfQ1ClHc/s72-c/language-comparison.png" height="72" width="72" /></entry><entry gd:etag="W/&quot;AkIFRXY8eCp7ImA9WhRRFkw.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-2140508966467114941</id><published>2011-11-29T18:44:00.000+08:00</published><updated>2011-11-30T10:01:54.870+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-30T10:01:54.870+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="conary" /><title>conary dir</title><content type="html">&lt;br /&gt;
Some conary recipe methods (including addArchive, Make, etc.) accept a "dir" parameter. It allows you to specify a custom directory within which to execute the action. What's confusing is that, its behavior is not so consistent (when dir is a relative directory).&lt;br /&gt;
&lt;br /&gt;
addArchive() by default works inside the "builddir", usually &lt;code&gt;~/conary/builds/foobar/&lt;/code&gt; (that is the buildPath; check your buildPath with `conary config |  grep buildPath`). So an explicit "dir" argument for addArchive is relative to the builddir.&lt;br /&gt;
&lt;br /&gt;
For Make(), MakeInstall(), etc., they work inside the "maindir", usually &lt;code&gt;~/conary/builds/foobar/foobar-1.0/&lt;/code&gt;. So "dir" for them is relative to maindir.&lt;br /&gt;
&lt;br /&gt;
Here is an example.&lt;br /&gt;
&lt;br /&gt;
Some time ago I needed to add an additional tarball to the conary package. This is what it takes.&lt;br /&gt;
&lt;pre style="background: #ffffff; color: black;"&gt;r&lt;span style="color: #808030;"&gt;.&lt;/span&gt;addArchive&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;'https://some/url/conary-bash-completion-0.2.tar.bz2'&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt; &lt;span style="color: #e34adc;"&gt;dir&lt;/span&gt;&lt;span style="color: #808030;"&gt;=&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;'%(maindir)s'&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;
r&lt;span style="color: #808030;"&gt;.&lt;/span&gt;Make&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #e34adc;"&gt;dir&lt;/span&gt;&lt;span style="color: #808030;"&gt;=&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;'conary-bash-completion-0.2'&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;
r&lt;span style="color: #808030;"&gt;.&lt;/span&gt;MakeInstall&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #e34adc;"&gt;dir&lt;/span&gt;&lt;span style="color: #808030;"&gt;=&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;'conary-bash-completion-0.2'&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;
&lt;/pre&gt;
The tarball has such a structure,&lt;br /&gt;
&lt;pre style="background: #ffffff; color: black;"&gt;$ tar tf conary&lt;span style="color: #808030;"&gt;-&lt;/span&gt;bash&lt;span style="color: #808030;"&gt;-&lt;/span&gt;completion&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;0.2&lt;/span&gt;&lt;span style="color: #008c00;"&gt;.&lt;/span&gt;tar&lt;span style="color: #008c00;"&gt;.&lt;/span&gt;bz2
conary&lt;span style="color: #808030;"&gt;-&lt;/span&gt;bash&lt;span style="color: #808030;"&gt;-&lt;/span&gt;completion&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;0.2&lt;/span&gt;&lt;span style="color: #808030;"&gt;/&lt;/span&gt;
conary&lt;span style="color: #808030;"&gt;-&lt;/span&gt;bash&lt;span style="color: #808030;"&gt;-&lt;/span&gt;completion&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;0.2&lt;/span&gt;&lt;span style="color: #808030;"&gt;/&lt;/span&gt;generate&lt;span style="color: #008c00;"&gt;.&lt;/span&gt;py
conary&lt;span style="color: #808030;"&gt;-&lt;/span&gt;bash&lt;span style="color: #808030;"&gt;-&lt;/span&gt;completion&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;0.2&lt;/span&gt;&lt;span style="color: #808030;"&gt;/&lt;/span&gt;README
conary&lt;span style="color: #808030;"&gt;-&lt;/span&gt;bash&lt;span style="color: #808030;"&gt;-&lt;/span&gt;completion&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;0.2&lt;/span&gt;&lt;span style="color: #808030;"&gt;/&lt;/span&gt;Makefile
&lt;/pre&gt;
So, the addArchive() call will extract the tarball at the maindir, &lt;code&gt;~/conary/builds/conary/conary-2.3/&lt;/code&gt;. The files will be available under &lt;code&gt;~/conary/builds/conary/conary-2.3/conary-bash-completion-0.2&lt;/code&gt;. And Make and MakeInstall will work inside that directory.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-2140508966467114941?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/L3ZOSIVnl0E" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2140508966467114941?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2140508966467114941?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/11/conary-dir.html" title="conary dir" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;AkIBRHs-eCp7ImA9WhRRFkw.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-7016433103500279921</id><published>2011-11-23T18:26:00.000+08:00</published><updated>2011-11-30T10:02:35.550+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-30T10:02:35.550+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="shell" /><title>whitespaces</title><content type="html">两个 shell 小技巧，处理带有空格的文件名。&lt;br /&gt;
&lt;br /&gt;
bash 里，用 for .. in (比如 for f in `cat some/file`; do ...) 或者其它方式 (比如 xargs, cat some/file | xargs ls -l) 处理文件的时候，如果文件名有空格，经常会遇到问题，因为本来是一行一行的文件会被当成一个长字符串，而 bash 和 xargs 在处理的时候，把空格和换行都当成分割符 (&lt;a href="http://tldp.org/LDP/abs/html/internalvariables.html"&gt;$IFS, internal field separator&lt;/a&gt;)。&lt;br /&gt;
&lt;br /&gt;
这时候可以改 $IFS。但是它的用法好像比较微妙。所以如果需求很简单，也有一些很简单的应对办法。以下举两例。&lt;br /&gt;
&lt;br /&gt;
1. &lt;code&gt;for f in `cmd`; do ...&lt;/code&gt; 可以换成 &lt;code&gt;cmd | while read f; do ...&lt;/code&gt;。比如，&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;cat some/file | while read f; do echo $f; done&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
2. xargs 可以利用 --delimiter=delim 参数，比如，&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;xargs -a some/file -d '\n' du -shc&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-7016433103500279921?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/av4mvJf987U" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/7016433103500279921?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/7016433103500279921?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/11/whitespaces.html" title="whitespaces" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;AkIMSX88cCp7ImA9WhRRFkw.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-2757276005973517360</id><published>2011-11-10T15:45:00.001+08:00</published><updated>2011-11-30T10:03:08.178+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-30T10:03:08.178+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="language" /><title>indefinite adjective</title><content type="html">什么叫 indefinite  adjective？&lt;br /&gt;
&lt;blockquote class="tr_bq"&gt;
An indefinite  adjective is an adjective formed from an

    indefinite pronoun.&lt;br /&gt;
&lt;br /&gt;
The most common indefinite pronouns are: all, any,
    anyone, anything, each, everybody, everyone, everything, few, many, nobody,
    none, one, several, some, somebody, and someone.&lt;br /&gt;
&lt;br /&gt;
When used as adjectives, these are known as "indefinite
    adjectives". &lt;i&gt;(&lt;a href="http://www.grammar-monster.com/glossary/indefinite_adjectives.htm"&gt;ref&lt;/a&gt;)&lt;/i&gt;&lt;/blockquote&gt;
嗯，&lt;i&gt;非限定性形容词&lt;/i&gt;。用作代词时是&lt;i&gt;非限定性代词 / indefinite pronoun&lt;/i&gt;，用作形容词就是&lt;i&gt;非限定性形容词&lt;/i&gt;。&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;非限定性&lt;/i&gt;，也就是表示泛指。注意，&lt;i&gt;“所有”&lt;/i&gt;，&lt;i&gt;“任何&lt;/i&gt;”也是泛指。&lt;br /&gt;
&lt;br /&gt;
法语中与英语类似，常见的 indefinite adjective (&lt;span class="short_text" id="result_box" lang="fr"&gt;&lt;span class="hps"&gt;&lt;a href="http://fr.wikipedia.org/wiki/Adjectif_ind%C3%A9fini"&gt;adjectif indéfini&lt;/a&gt;)&lt;/span&gt;&lt;/span&gt; 包括 autre, aucun, certain, chaque, divers, différents, maint, même, n'importe, plusieurs, quelque, quelconque, tout, 等等。&lt;br /&gt;
&lt;br /&gt;
tout 貌似是个很麻烦的东西，以后再整理。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-2757276005973517360?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/qnurGBKIxsE" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2757276005973517360?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2757276005973517360?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/11/indefinite-adjective.html" title="indefinite adjective" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;Ak8BQ3k_eyp7ImA9WhRRFkw.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-3680699759584247101</id><published>2011-10-24T22:35:00.002+08:00</published><updated>2011-11-30T10:07:32.743+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-30T10:07:32.743+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vim" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="git" /><category scheme="http://www.blogger.com/atom/ns#" term="politics" /><category scheme="http://www.blogger.com/atom/ns#" term="book" /><title>agile</title><content type="html">M同学问我，“那美国是资本主义吗?”&lt;br /&gt;
&lt;br /&gt;
这个问题本身就是错误的。分类不是这样分的。就好比现在我提出个理论，把所有的水果分成红色主义和绿色主义，那香蕉是哪个主义的？假设现在香蕉卖的特别好，那是因为它采取了红色主义，还是因为它采取了绿色主义？&lt;br /&gt;
&lt;br /&gt;
所以改革开放最大的成就之一就是放弃了以意识形态作为判断标准。以事实作为评判依据，意味着鼓励尝试。(当然，此党的本质决定了这种鼓励不会深入。)&lt;br /&gt;
&lt;br /&gt;
从脑子里想出来的“主义”几乎不可能是完美的，所以选了一个以某一主义为纲的政党上台，从一开始就决定了我们悲惨的结局。&lt;br /&gt;
&lt;br /&gt;
开发软件，尚且无法完全按照计划来实行，更何况治国呢？最伟大的开国者不在于能提出完美的方案，而在于能制定完美的规则。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-3680699759584247101?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/20JQYbIesR0" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/3680699759584247101?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/3680699759584247101?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/10/agile.html" title="agile" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;DEMNQno7fip7ImA9WhdVGE8.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-4872903800966979619</id><published>2011-09-23T18:30:00.000+08:00</published><updated>2011-09-24T09:08:13.406+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-24T09:08:13.406+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="django" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>django simple pager</title><content type="html">Here is a short piece of code to help write a simple pager (or paginator) in django.&lt;br /&gt;
&lt;br /&gt;
Its main function is to insert ellipses at the right places. (Of course! What's hard about a pager anyway). The result is like the one you see on &lt;a href="http://stackoverflow.com/"&gt;stackoverflow.com&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-cfJ4EImgfgE/TnwdHVOCkcI/AAAAAAAAASE/sVsfnnje4l8/s1600/pager-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-cfJ4EImgfgE/TnwdHVOCkcI/AAAAAAAAASE/sVsfnnje4l8/s1600/pager-1.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-Ieh8qufE-H4/TnwdHV7oB4I/AAAAAAAAASM/E4dKu4O0RCk/s1600/pager-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-Ieh8qufE-H4/TnwdHV7oB4I/AAAAAAAAASM/E4dKu4O0RCk/s1600/pager-2.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The code (See the original post for the code, if you are using a feed reader such as Google Reader):&lt;br /&gt;
&lt;script src="https://gist.github.com/1231609.js"&gt;
 
&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-4872903800966979619?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/ANe0UJPIt1w" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/4872903800966979619?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/4872903800966979619?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/09/django-simple-pager.html" title="django simple pager" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-cfJ4EImgfgE/TnwdHVOCkcI/AAAAAAAAASE/sVsfnnje4l8/s72-c/pager-1.png" height="72" width="72" /></entry><entry gd:etag="W/&quot;Ck8DRXo6fip7ImA9WhdWFE0.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-2469721062443877400</id><published>2011-09-07T18:26:00.000+08:00</published><updated>2011-09-07T21:07:54.416+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-07T21:07:54.416+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>python get relative time</title><content type="html">Here is a little piece of python code to get the "age" of a timestamp (in other words, how much time has elapsed since then). Like what you see on Hacker News or reddit, "8 hours ago", "1 day ago", etc.&lt;br /&gt;
&lt;br /&gt;
The job of this code is to figure out the "8 hours" and "1 day" part.&lt;br /&gt;
&lt;br /&gt;
Here is the code (hosted as a gist on github).&lt;br /&gt;
&lt;br /&gt;
&lt;script src="https://gist.github.com/1199964.js?file=relative_time.py"&gt;
&lt;/script&gt;&lt;br /&gt;
&lt;br /&gt;
I think I got some inspiration from someone's blog on the internet, but I can't find it now. Anyway the codes don't look alike IIRC and it's short, and I put it in the public domain. Do whatever you want.&lt;br /&gt;
&lt;br /&gt;
The function is simple and it's not very robust, e.g. it doesn't handle the case when you pass in a date in the future. But it should be easy to extend.&lt;br /&gt;
&lt;br /&gt;
And it only works for English. For something that can do i18n, you may need &lt;a href="http://www.gnu.org/s/hello/manual/gettext/Plural-forms.html"&gt;gettext&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-2469721062443877400?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/-ZSQCe7-kwc" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2469721062443877400?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2469721062443877400?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/09/python-get-relative-time.html" title="python get relative time" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;CUAHRXcyfCp7ImA9WhdQGU4.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-5311738448675941845</id><published>2011-08-20T12:23:00.000+08:00</published><updated>2011-08-21T21:35:34.994+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-21T21:35:34.994+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="git" /><title>git notes</title><content type="html">Now git looks even more powerful in my eyes. &lt;code&gt;git-notes&lt;/code&gt; gives you the ability to attach some information to the commits. When I came upon this when searching blindly on Google, I thought, "Wow, this is damn cool. Exactly what I'm looking for!"&lt;br /&gt;
&lt;br /&gt;
For the details of this command, see &lt;a href="http://progit.org/2010/08/25/notes.html"&gt;here on Pro Git&lt;/a&gt; or &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-notes.html"&gt;in the git manual&lt;/a&gt;. This post is about how I used it.&lt;br /&gt;
&lt;br /&gt;
As it always does, git gives the command lots of flexibility. See it for yourself. But what I needed is simple. I don't care about all those feature. I just want &lt;code&gt;"git notes add"&lt;/code&gt; and &lt;code&gt;"git notes show"&lt;/code&gt;, which will help me attach information to the HEAD and later retrieve it.&lt;br /&gt;
&lt;br /&gt;
This is my use case. I'm converting conary repositories (which stores the conary source packages) into git repositories. And I want incremental conversion, i.e. when the conary repo gets new commits, I want to add them on top of the existing git repo, without generating it all once again.&lt;br /&gt;
&lt;br /&gt;
The problem is, there is no way to tell the revisions of the conary packages from the git revisions (neither the other way around). The history in the git repo is identical with that in the conary repo. The commit messages are the same and the commit body are the same. But there is no way to tell which conary revision is which git revision.&lt;br /&gt;
&lt;br /&gt;
Which means, I don't know the progress of the conversion, so I don't know where to resume when new commits come into the conary repo.&lt;br /&gt;
&lt;br /&gt;
I thought about storing the progress in an external file, but that's fragile. What would the git repo was changed by someone else than my script? I thought about storing the conary revision in each of the git commit messages. But that would break my goal of keeping the history untouched.&lt;br /&gt;
&lt;br /&gt;
Then blindly and without much hope, I &lt;a href="http://www.google.com/search?q=git+store+extra+info+in+commit"&gt;searched for "git store extra info in commit" on google&lt;/a&gt;. The first result is some mailing list discussion. And someone mentioned &lt;code&gt;"git notes"&lt;/code&gt;. Voilà!&lt;br /&gt;
&lt;br /&gt;
How I used it is actually simple. When one pass of conversion is done, I store the revision of each package that's been converted in a git note. And the next time, I just fetch the note and retrieve the revisions :-)&lt;br /&gt;
&lt;br /&gt;
And I'm grateful that git doesn't complain when I store a 52KB note :)&lt;br /&gt;
&lt;br /&gt;
The code of my script is available &lt;a href="https://github.com/zhangsen/cvc2git/blob/master/cvc2git#L216"&gt;at github&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-5311738448675941845?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/kqVLmXyjukU" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/5311738448675941845?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/5311738448675941845?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/08/git-notes.html" title="git notes" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;CkIGQnk-eCp7ImA9WhdSGE4.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-2262542518445652764</id><published>2011-07-27T17:09:00.001+08:00</published><updated>2011-07-28T13:22:03.750+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-28T13:22:03.750+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="web" /><title>web.py: get auto-increment value after db.insert</title><content type="html">This is probably too simple, so no one ever bothered to write about it. (Or I couldn't come up with the proper keywords for Google).&lt;br /&gt;
&lt;br /&gt;
The situation is simple. I have a table where the primary key is some auto-incrementing ID number (in the case of postgresql, with the primary key called &lt;code&gt;nid&lt;/code&gt;, the definition is &lt;code&gt;nid serial primary key&lt;/code&gt;). After inserting a record into the table, I want to know what ID it has got.&lt;br /&gt;
&lt;br /&gt;
Turns out it's very simple. I need only to pass a custom &lt;code&gt;seqname&lt;/code&gt; to db.insert().&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
nid = db.insert("tablename", seqname="tablename_nid_seq",...)&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
For the &lt;code&gt;serial&lt;/code&gt; column, postgresql creates a sequence automatically and assigns it a particularly constructed name. More details at &lt;a href="http://neilconway.org/docs/sequences/"&gt;FAQ: Using Sequences in PostgreSQL&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
This is probably not the best style (I'm hard-coding the seqname in the source code), and I'm not even sure if it's the right way. But at least I can proceed with my prototyping and hacking now :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-2262542518445652764?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/irBf031cgD4" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2262542518445652764?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2262542518445652764?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/07/webpy-get-auto-increment-value-after.html" title="web.py: get auto-increment value after db.insert" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;DUIDRXc9cCp7ImA9WhRSGEg.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-6821176862863209160</id><published>2011-07-21T16:53:00.000+08:00</published><updated>2011-11-21T14:39:34.968+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-21T14:39:34.968+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><title>Resize partition</title><content type="html">第一次成功地调整分区的大小，所以写篇文章记录一下。&lt;br /&gt;
&lt;br /&gt;
我依稀记起了刚用 Linux 的时候，大概是在 06 或者 07 年吧，当时也是要调整分区大小，结果一番操作下来，启动系统，发现硬盘上啥都没有了。所以最后只能重装系统。现在再来做这件事，虽然不是轻车熟路，但也是不慌不忙了 :P&lt;br /&gt;
&lt;br /&gt;
我要给一个 qemu 虚拟机调整分区，所以下文第一部分是关于 qemu 的。第二部分应该能适用于一般的在真正的硬件上的系统。&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
1. 调整 qemu 虚拟磁盘的大小&lt;/h2&gt;
&lt;br /&gt;
我现在用了一个 12G 的虚拟磁盘给虚拟机用，里边装了个 Linux，根分区大约 10G。我想把根分区扩大 4G。&lt;br /&gt;
&lt;br /&gt;
所以首先要扩大虚拟磁盘的大小。Google 一下可以找到很多办法，我采取的是&lt;a href="http://kevin.deldycke.com/2007/04/how-to-grow-any-qemu-system-image/"&gt;这里&lt;/a&gt;提到的，先创建一个 4G 的文件，然后把它 cat 到原磁盘文件的末尾。这个看起来比较安全 (我一直比较惧怕 dd)。&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
$ dd if=/dev/zero of=zeros.raw bs=1024k count=4096&lt;br /&gt;
&lt;br /&gt;
$ cat foresight.img zeros.raw &amp;gt; new-foresight.img&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
用 &lt;code&gt;cat zeros.raw &amp;gt;&amp;gt; foresight.img&lt;/code&gt; 估计也可以。&lt;br /&gt;
&lt;br /&gt;
(如果磁盘文件不是 raw 格式的，可能需要先把磁盘文件从 qcow 等格式转换为 raw 格式；可用 &lt;code&gt;qemu-img info foresight.img&lt;/code&gt; 查看)。&lt;br /&gt;
&lt;br /&gt;
到这儿，我的虚拟磁盘文件 (foresight.img) 就从 12G 变成 16G 了。以上都是在 host 机器上做的，下一步就是在虚拟机里调整分区大小。&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
2. 调整分区大小&lt;/h2&gt;
&lt;br /&gt;
为了能够在不挂载的条件下进行操作 (以免出问题，fdisk 实际上好像也要求分区不能挂载)，需要用另一个系统来启动机器。用 liveCD 光盘或者 liveUSB 都可以，我是直接用的 Foresight Linux 的安装盘，因为它支持一个 rescue 模式 (跟 liveCD 差不多，但是命令行的，速度快一点)。&lt;br /&gt;
&lt;br /&gt;
普通安装的话，把光盘放光驱就可以了。用 qemu 的话，传一个 -cdrom 选项。(同时也把启动时的菜单打开，以便能选择从光驱启动。)&lt;br /&gt;
&lt;code&gt;&lt;br /&gt;
-cdrom /path/to/foresight/iso -boot menu=on&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
进入后，不用挂载机器上原来的分区。&lt;br /&gt;
&lt;br /&gt;
先来点小知识。对 Linux 来说，分区 (partition) 和文件系统 (filesystem) 是分开的，前者指的是硬件，后者指的是软件。文件系统创建在分区上，它的大小可以比分区更小。我的最终目的是调整文件系统的大小，因为操作系统是安装在文件系统中的。&lt;br /&gt;
&lt;br /&gt;
所以要为操作系统提供更多的可用空间，需要分两步：1，扩大硬盘分区；2，扩大文件系统。前者用 fdisk 完成，后者用 resize2fs。(有的工具比如 parted 和 gparted 把两步合在一块了)。&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
2.1 扩大分区&lt;/h3&gt;
&lt;br /&gt;
&lt;code&gt;# fdisk /dev/sda&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
执行 fdisk。把原来的分区删掉，然后创建一个新的分区。新分区的开头要跟旧分区一样，长度要比旧分区大。&lt;br /&gt;
&lt;br /&gt;
由于我当初分区的时候把根分区放在了 swap 之前，所以我要先把 swap 分区删掉，最后再创建一个新的 swap。&lt;br /&gt;
&lt;br /&gt;
fdisk 不会修改分区里面的东西，所以这样就把分区扩大了。其上的文件系统没有变，还是原来的大小。&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
2.2 扩大文件系统&lt;/h3&gt;
&lt;br /&gt;
&lt;code&gt;# resize2fs -f /dev/sda2&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
resize2fs 把 sda2 上的文件系统扩大到跟分区一样大。&lt;br /&gt;
&lt;br /&gt;
至此就搞定了。执行下 sync 重启即可。&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
2.3 其他&lt;/h3&gt;
&lt;br /&gt;
由于我上边重建了 swap 分区，所以要重新格式化 swap。&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;$ sudo mkswap /dev/sda3&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
我系统中原来的 fstab 是用 label 来引用分区。由于 label 没有了，所以把它改成直接使用 /dev/sda3：&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&lt;u&gt;LABEL=SWAP-sda3&lt;/u&gt;         swap                    swap    defaults        0 0&lt;br /&gt;
&lt;u&gt;/dev/sda3&lt;/u&gt;                          swap                    swap    defaults        0 0&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
应该也可以重新创建 label 的，但是由于我不知道怎么做，就只好这样了。&lt;br /&gt;
&lt;br /&gt;
我是在系统启动之后执行这两步的，也可以在 rescue 系统中做。&lt;br /&gt;
&lt;br /&gt;
如果用的是 lvm，就更省事儿了，不过我一直不会用...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-6821176862863209160?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/nNJzIUu1kbI" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/6821176862863209160?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/6821176862863209160?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/07/resize-partition.html" title="Resize partition" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;DEMMQ3Y9fyp7ImA9WhdTEU8.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-1871843874295825587</id><published>2011-07-08T20:04:00.000+08:00</published><updated>2011-07-08T20:01:22.867+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-08T20:01:22.867+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>Supybot JIRA plugin</title><content type="html">I have been working on a small project recently, a JIRA plugin for supybot. Today I feel it's feature complete (at least for its use in the Foresight Linux IRC channels). So time for a blog post :-)&lt;br /&gt;
&lt;br /&gt;
Firstly the code is &lt;a href="https://github.com/zhangsen/supybot-jira"&gt;available at GitHub&lt;/a&gt;. It's easy to setup (hopefully). See JIRA/README.txt for details. I won't repeat it here in order to minimize duplication.&lt;br /&gt;
&lt;br /&gt;
The main (and only) function is to monitor the chatting in the channels and detect when people mention an issue number. Then the bot queries the JIRA and posts a summary of the issue to the channel.&lt;br /&gt;
&lt;br /&gt;
It supports multiple JIRA installations. For example in #foresight our bot knows about the Foresight JIRA, as well as the rPath JIRA, so that we can get information about conary issues (which is maintained outside Foresight Linux at rPath).&lt;br /&gt;
&lt;br /&gt;
There are a few configuration options too. The format of the issue summary can be customized. There is also a timeout option (default to 5 minutes); the bot won't report the same issue again and again, and spam the channel.&lt;br /&gt;
&lt;br /&gt;
If you want to play with it, stop by #foresight and find the bot there (it may be called foresight, flbot, fleabot or other names). Then &lt;i&gt;/query&lt;/i&gt; the bot and give it some commands (e.g. FL-12, KDE-34, etc.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-1871843874295825587?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/6Xi32zHHkCw" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/1871843874295825587?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/1871843874295825587?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/07/supybot-jira-plugin.html" title="Supybot JIRA plugin" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;AkUHQ3g-eyp7ImA9WhZaFEU.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-159439451295429550</id><published>2011-07-01T10:40:00.002+08:00</published><updated>2011-07-01T10:43:52.653+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-01T10:43:52.653+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="politics" /><title>Birthday of THE PARTY</title><content type="html">此文没啥新意，但是党的生日来了，我觉得我们都应该写篇文章，抒发一下自己对这个事物的看法。&lt;br /&gt;
&lt;br /&gt;
写这篇文章的冲动来自于：&lt;a href="http://www.infzm.com/content/60713"&gt;听俞正声上党课——“执政者的声音”&lt;/a&gt;。&lt;br /&gt;
&lt;br /&gt;
显然这就是很多人内心真实的想法了，抛去冠冕堂皇，这不止是他们做的秀，也是他们内心真正相信的东西。&lt;br /&gt;
&lt;br /&gt;
&amp;gt; 怎么样在复杂的社会环境中间保持一种政治上的坚定性，“是一件不容易的事情”。&lt;br /&gt;
&lt;br /&gt;
“政治上的坚定”，这种说法可真奇怪。为什么要坚定？党自身的想法都不是固定的。跟所有的党一样 (且看美国当今两党的变化历程，&lt;a href="http://zh.wikipedia.org/wiki/%E6%B0%91%E4%B8%BB%E5%85%9A_%28%E7%BE%8E%E5%9B%BD%29"&gt;民主党&lt;/a&gt;|&lt;a href="http://zh.wikipedia.org/wiki/%E5%85%B1%E5%92%8C%E9%BB%A8_%28%E7%BE%8E%E5%9C%8B%29"&gt;共和党&lt;/a&gt;)，党的理念在不停的变化。一个人，作为一个个体，有着自己的大脑，为什么要“坚定”在一个不停变化的组织旁边？&lt;br /&gt;
&lt;br /&gt;
而且现实世界中的决策从来不是非黑即白，事情的两面很难说出孰优孰劣。申纪兰确实是够坚定的。&lt;br /&gt;
&lt;br /&gt;
只能说这是一种愚昧的坚定。&lt;br /&gt;
&lt;br /&gt;
&amp;gt; 中共诞生，就是要为劳苦大众打天下，就是不能让社会、官僚们熟视无睹群众死活的状况在中国继续下去，所以才产生了共产党。&lt;br /&gt;
&lt;br /&gt;
“社会、官僚们熟视无睹群众死活”。这是教科书上向来的说法。当时的生活确实不好，但也不至于这么概括吧 (其实应用于当下更合适)。从建国大业和建党伟业来看，当时的政治气氛比现在可是好多了。&lt;br /&gt;
&lt;br /&gt;
至于党的目的，这么概括就更是洗脑了。毫无疑问当时一些纯洁的大学生确实是这么想的，但是要说“党”的目的是“为劳苦大众打天下”，也太没脑子了。对权力的争夺才是最根本的目的。从本质上讲，中共跟历代的农民起义没有区别，不过是提出了更新的口号而已。从陈胜吴广，到宋江，到李自成，到义和团，造反的农民们提出的口号代代在刷新。毛泽东也就配跟这些人相提并论。&lt;br /&gt;
&lt;br /&gt;
而且这句口号在今天看来，就是十足的讽刺了。再过一阵，建党大业都会成为禁片。&lt;br /&gt;
&lt;br /&gt;
&amp;gt; 解放战争的胜利...根本上是人民群众的拥护和支持。&lt;br /&gt;
&lt;br /&gt;
刘邦的胜利，根本上是人民群众的拥护和支持。&lt;br /&gt;
&lt;br /&gt;
&amp;gt; 我对毛主席是非常尊敬的，虽然他犯了这么大的错误。&lt;br /&gt;
&lt;br /&gt;
40后和50后这代人很是奇怪，他们在童年一方面接受着党的教化 (洗脑)，一方面眼睁睁看着党在行凶，看着自己的家人受迫害。结果他们就形成了上边这种畸形的心理。这不就是斯德哥尔摩综合征吗？与&lt;a href="http://zh.wikipedia.org/zh-cn/%E6%96%AF%E5%BE%B7%E5%93%A5%E5%B0%94%E6%91%A9%E7%BB%BC%E5%90%88%E7%97%87"&gt;斯德哥尔摩综合征&lt;/a&gt;的特征和四大历程如此符合。&lt;br /&gt;
&lt;br /&gt;
毛泽东既然知道自己做错了，造成了很大的破坏，为什么不引咎辞职？毫无疑问，太祖作为太祖，一个独裁者，认为天下是自己的。就跟皇帝一样，做错点事，让一些草民丢掉性命，事后自责一下就够了，他们绝对不会想到自己应该下台，受人唾弃。&lt;br /&gt;
&lt;br /&gt;
当时的最高权力机构，既然认定毛泽东做错了，为什么不把他判罪？当然，原因还是跟封建王朝一样。&lt;br /&gt;
&lt;br /&gt;
如今六七十岁那些人是精神上最分裂的一代。&lt;br /&gt;
&lt;br /&gt;
&amp;gt; 党也不回避自己的问题和失误。&lt;br /&gt;
&lt;br /&gt;
这。。。只能说是赤裸裸的撒谎了。&lt;br /&gt;
&lt;br /&gt;
&amp;gt; 中国大陆要是多党，可能就会把中国大陆变成了政客权谋的竞技场。&lt;br /&gt;
&lt;br /&gt;
中国大陆现在难道不是政客权谋的竞技场？而且把活跃的政治活动说成是混乱，像 CCTV-4 这种党媒整天刷黑台湾，其实只能说明党的内心虚弱到了何种程度。&lt;br /&gt;
&lt;br /&gt;
&amp;gt; 如果党本身是软弱无力的，这个党不会有希望。&lt;br /&gt;
&lt;br /&gt;
党很害怕。&lt;br /&gt;
&lt;br /&gt;
&amp;gt; 要敢于讲真话，你敢不敢于在领导面前发表你的看法？&lt;br /&gt;
&lt;br /&gt;
这一代人眼里，“领导”就是主宰一切的神。&lt;br /&gt;
&lt;br /&gt;
仔细想想，什么是“党”？党不是千万党员，不是总书记，不是这个职位或那个职位。党不是一个或几个人。党是一种理念，党是一种非物质。党是人性中最邪恶的一面，是所有党员最邪恶的一面的合集。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-159439451295429550?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/QGSTzcJLe94" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/159439451295429550?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/159439451295429550?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/07/birthday-of-party.html" title="Birthday of THE PARTY" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;Ck4ESH07cSp7ImA9WhZaEkk.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-3821290824501371478</id><published>2011-06-28T14:01:00.000+08:00</published><updated>2011-06-28T14:01:49.309+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-28T14:01:49.309+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>How to understand recursion</title><content type="html">这是从 ANSI Common Lisp 里看到的一段。本来想在豆瓣上写个读书笔记的，但是我觉得这个太重要了，应该写篇文章来记录一下。&lt;br /&gt;
&lt;br /&gt;
很多人（包括我）觉得递归难以理解，因为我们大脑里对“函数”的模型不对。基于这种模型去思考，整个递归过程很容易变成一团浆糊。&lt;br /&gt;
&lt;br /&gt;
那我们潜意识中是怎样对待“函数”的呢？书里一般会说函数是一种抽象，所以我们就把函数当作一个黑盒子，或者按照 Paul 的说法，当作一个机器。参数是这个机器的原材料；机器有时候会把部分工作外包给别的机器；最后的产品被组装起来，也就是函数的返回值。这就是我们大脑里的模型。&lt;br /&gt;
&lt;br /&gt;
遇到递归函数的时候我们还是这样思考的，但是现在，这种抽象反而让事情更难以理解。一个机器已经在运转了，怎么还能把一部分活儿外包给自己？它们生成的产品又是怎么组装到一块的？&lt;br /&gt;
&lt;br /&gt;
比如这样一个简单的递归函数，判断一个对象是否在一个列表中：&lt;br /&gt;
&lt;pre bgcolor="#ffffff" text="#ffff00"&gt;&lt;font face="monospace"&gt;
&lt;font color="#008000"&gt;def&lt;/font&gt; &lt;font color="#0000c0"&gt;member&lt;/font&gt;(obj, lst):
    &lt;font color="#008000"&gt;if&lt;/font&gt; &lt;font color="#008000"&gt;not&lt;/font&gt; lst:
        &lt;font color="#008000"&gt;return&lt;/font&gt; &lt;font color="#0000c0"&gt;False&lt;/font&gt;
    &lt;font color="#008000"&gt;if&lt;/font&gt; lst[&lt;font color="#008080"&gt;0&lt;/font&gt;] == obj:
        &lt;font color="#008000"&gt;return&lt;/font&gt; lst
    &lt;font color="#008000"&gt;return&lt;/font&gt; member(obj, lst[&lt;font color="#008080"&gt;1&lt;/font&gt;:])
&lt;/font&gt;
&lt;/pre&gt;按照以前的习惯，我的大脑会尝试着展开每次递归调用。结果不必说，一团乱麻。&lt;br /&gt;
&lt;br /&gt;
Paul 讲了一个更好的方法，也就是把函数当作一个处理过程 (process)。上边的函数可以转换成这样一个用自然语言描述的过程：&lt;br /&gt;
&lt;br /&gt;
1. 首先检查 lst 是否为空，如果是空的，obj 当然不是这个列表的元素。处理完毕。&lt;br /&gt;
&lt;br /&gt;
2. 否则，检查 obj 是否是 lst 的第一个元素。如果是的话，obj 是 lst 的元素。&lt;br /&gt;
&lt;br /&gt;
3. 否则，当且只当 obj 是 lst 剩余部分的一个元素的时候，它是 lst 的一个元素。&lt;br /&gt;
&lt;br /&gt;
这样是不是很直白？使用自然语言能帮助我们理解一个递归函数。&lt;br /&gt;
&lt;br /&gt;
再举个现实世界中的例子。假设现在有个党史学家，他想研究一下党员数量的变化。他研究的过程可能是这样的：&lt;br /&gt;
&lt;br /&gt;
1. 找一份资料。&lt;br /&gt;
&lt;br /&gt;
2. 寻找跟党员数量相关的信息&lt;br /&gt;
&lt;br /&gt;
3. 如果这份资料提到了其他可能有用的资料，研究这些资料。&lt;br /&gt;
&lt;br /&gt;
显然这是个递归的过程。对一个过程来说，递归是很自然的。现实世界中有各种各样的递归过程。所以把函数想成一个过程，而不是一个机器，会帮我们更好的理解递归。&lt;br /&gt;
&lt;br /&gt;
再回到上边的 member 函数，不要把它想成一个用于判断对象是否在列表中的机器。把它当作一组进行判断的规则，顺着这组规则走下来，我们就能做出正确的判断。&lt;br /&gt;
&lt;br /&gt;
(当然第二个例子是本文作者虚拟的。在现实世界中，党说党员数量是怎么变化的，党员数量&lt;a href="http://www.quotedb.com/quotes/3947"&gt;就是&lt;/a&gt;怎么变化的。)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-3821290824501371478?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/QNN1hSlDiiQ" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/3821290824501371478?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/3821290824501371478?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/06/how-to-understand-recursion.html" title="How to understand recursion" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;AkABRX07cSp7ImA9WhRRFkw.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-4895098118170301386</id><published>2011-03-17T22:27:00.004+08:00</published><updated>2011-11-30T10:05:54.309+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-30T10:05:54.309+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="vim" /><category scheme="http://www.blogger.com/atom/ns#" term="git" /><title>Working with Different Coding Styles</title><content type="html">问题最近看代码看得相当的 high，有时候也写上几行，再没有了那种不能写代码的郁闷。工作中当然还是没有多少 coding 的机会，不过我现在能挤出时间，尽量增加跟代码的接触 (感谢开明的老板)，所以工作心情好多了。这里记录此过程中一个非技术的小问题。&lt;br /&gt;
&lt;br /&gt;
因为接触了好几个开源项目 (&lt;a href="http://apprenticeship-patterns.labs.oreilly.com/ch05.html#expand_your_bandwidth"&gt;Expand Your Bandwidth&lt;/a&gt;)，而每个都有不同的代码风格，导致我写代码的时候有点不方便。如何缩进 (或者说 tab 键的处理) 是主要的问题，有的用 4 个空格缩进 (比如多数的 python 代码), 有的用 8 个空格 (比如 systemd), 有的用真正的 tab (比如 Linux kernel, packagekit)。但是对于 vim 来说，配置只能有一个，没法照顾到所有的情况。&lt;br /&gt;
&lt;br /&gt;
我能想到的解决办法有这么几个：&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;在文件头部指定代码风格，比如 &lt;code&gt;"Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8"&lt;/code&gt;。这叫 &lt;b&gt;mode line&lt;/b&gt;，vim 和 emacs 都支持，但是两者的格式却不一样，上边那个是 emacs 的，要是 vim 的话，得再添一行，&lt;code&gt;"vim: set ts=8 sw=4 tw=0:"&lt;/code&gt;。鉴于此，不能指望每个项目在每个文件里为每种编辑器写一行 mode line。systemd 就只考虑了 emacs，因为 Lennart Poettering 用的是 emacs。&lt;/li&gt;
&lt;li&gt;上面的问题有两个办法，1) 学习 emacs, 2) 用这个&lt;a href="http://www.vim.org/scripts/script.php?script_id=3381"&gt; vim 插件&lt;/a&gt;，让 vim 识别 emacs 的 mode line。1) 就算了... 但是 2) 基本上也行不通，因为有相当多的项目根本就没有任何的 mode line。&lt;/li&gt;
&lt;li&gt;vim 在读取配置的时候，能够识别当前目录下的配置文件。这样就可以为每个工程加一个 .vimrc，在里边指定本工程的代码风格。&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;/ul&gt;&lt;h3&gt;方案&lt;/h3&gt;第一跟第二条属于自己控制不了的，最后一个还比较靠谱。不过 vim 默认不会读取当前目录下的配置文件。因此首先要在 ~/.vimrc 里添加这么两行 (&lt;a href="http://damien.lespiau.name/blog/2009/03/18/per-project-vimrc/"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;引用&lt;/span&gt;&lt;/a&gt;)：&lt;br /&gt;
&lt;pre&gt;set exrc   " enable per-directory .vimrc files
set secure   " disable unsafe commands in local .vimrc files
&lt;/pre&gt;第二行是为安全起见 (&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;因为 vimrc 里的东西是被 vim _执行_ 的，所以可以被用作特洛伊木马&lt;/span&gt;)。&lt;br /&gt;
&lt;br /&gt;
然后写各工程的 .vimrc，这些都不会太长，因为只需要指定少数几个选项，比如 expandtab 和 shiftwidth。&lt;br /&gt;
&lt;pre&gt;$ cat .vimrc 
autocmd FileType c set noexpandtab shiftwidth=8
&lt;/pre&gt;这个配置适合 packagekit，用真正的 tab 进行缩进 (只针对 C 文件；工程里还有 python 文件，仍然使用 vim 的全局配置)。&lt;br /&gt;
&lt;br /&gt;
剩下的一个问题是，git status 的时候说有 untracked file，看起来实在不够清爽 :-) 本来可以让 git 忽略掉 .vimrc，但是项目里的 .gitignore 不是我能掌控的。不过，记住我们用的是 git :-) 用户可以指定全局的 gitignore 文件 (&lt;a href="http://lists.freedesktop.org/archives/systemd-devel/2011-March/001517.html"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;引用&lt;/span&gt;&lt;/a&gt;)。&lt;br /&gt;
&lt;pre&gt;$ git config --global core.excludesfile '~/.gitignore'
&lt;/pre&gt;再写好 gitignore，&lt;br /&gt;
&lt;pre&gt;$ cat ~/.gitignore 
.vimrc
&lt;/pre&gt;这样，就 OK 了!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-4895098118170301386?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/0T6UZy4Te5A" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/4895098118170301386?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/4895098118170301386?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/03/working-with-different-coding-styles.html" title="Working with Different Coding Styles" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;D0UFSXo4fSp7ImA9Wx9aF0s.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-2648592501329614808</id><published>2011-03-10T21:43:00.002+08:00</published><updated>2011-03-10T21:53:38.435+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-10T21:53:38.435+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="git" /><title>Git remote add</title><content type="html">今天打算下载 &lt;a href="http://git.kernel.org/?p=linux/kernel/git/airlied/drm-2.6.git;a=summary"&gt;DRM 的源代码&lt;/a&gt;，但是公司的网络访问 git.kernel.org 特别慢。而内核的源码树，加上所有的修改历史，大概有 1GB 吧，就算 git 能够先压缩再下载，也得几百兆。可怜下载速度只有十几 KB 每秒。再联想到 git 不能续传...&lt;br /&gt;
&lt;br /&gt;
公司倒是有自己的内核源码树，就在北京本地的服务器上。从那儿下载能有十几 MB 每秒，所以花几十秒钟就可以了。怎么办呢？毕竟两个源码树肯定是大同小异的。&lt;br /&gt;
&lt;br /&gt;
这，就是 git 的强大之处了。且看命令:&lt;code&gt;&lt;br /&gt;
$ &lt;b&gt;git clone&lt;/b&gt; git://internal/kernel-tree&lt;br /&gt;
$ cd kernel-tree&lt;br /&gt;
&lt;br /&gt;
$ &lt;b&gt;git remote add&lt;/b&gt; airlied-drm git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git&lt;br /&gt;
&lt;br /&gt;
$ &lt;b&gt;git fetch&lt;/b&gt; airlied-drm drm-next:&lt;b&gt;drm-next&lt;/b&gt;&lt;br /&gt;
remote: Counting objects: 284642, done.&lt;br /&gt;
remote: Compressing objects: 100% (55324/55324), done.&lt;br /&gt;
remote: Total 261757 (delta 210979), &lt;b&gt;reused 253047&lt;/b&gt; (delta 203096)&lt;br /&gt;
Receiving objects: 100% (261757/261757), &lt;b&gt;75.90 MiB&lt;/b&gt; | 10 KiB/s, done.&lt;br /&gt;
Resolving deltas: 100% (210979/210979), completed with 8754 local objects.&lt;br /&gt;
From git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6&lt;br /&gt;
&amp;nbsp;&lt;b&gt;* [new branch]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; drm-next&amp;nbsp;&amp;nbsp; -&amp;gt; drm-next&lt;/b&gt;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
这样就在本地得到了一个 drm-next 分支，用来追踪 airlied 的 DRM 源码树。 同时 master 分支仍然是追踪公司自己的源码树。两者互不干扰，用 git checkout 来切换就行了。&lt;br /&gt;
&lt;br /&gt;
也就是说，一个 git 仓库可以有多个 remote，而各个 remote 既相互独立，又可以共享数据。用上面的办法只需要下载 75 兆的数据，从输出中可以看到 git 确实 "reuse" 了一些东西。&lt;br /&gt;
&lt;br /&gt;
再跟直接的 git clone 比较一下，objects 的数量有相当大的区别 (当然，我不确定这跟实际的下载量是不是一回事)：&lt;code&gt;&lt;br /&gt;
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git&lt;br /&gt;
Cloning into drm-2.6...&lt;br /&gt;
remote: Counting &lt;b&gt;objects: 1908681&lt;/b&gt;, done.&lt;br /&gt;
remote: Compressing objects: 100% (309630/&lt;b&gt;309630&lt;/b&gt;), done.&lt;br /&gt;
^Cceiving objects:&amp;nbsp;&amp;nbsp; 0% (1198/&lt;b&gt;1908681&lt;/b&gt;), 500.00 KiB | 11 KiB/s&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
git，真是无比强大...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-2648592501329614808?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/qadyn1SdFBY" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2648592501329614808?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2648592501329614808?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/03/git-remote-add.html" title="Git remote add" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;CkcNRXY5fip7ImA9WhZUFU8.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-4701078540769924926</id><published>2011-03-05T17:08:00.002+08:00</published><updated>2011-06-08T16:01:34.826+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-08T16:01:34.826+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="language" /><title>What does the Mc in McDonald mean?</title><content type="html">今天又遇到一个加拿大人，姓是以 Mc 开头 (McMaster)。于是请教了一下这是为什么，终于明白了这种分两段的姓的意思。&lt;br /&gt;
&lt;br /&gt;
Mac, Mc, (甚至简写成 M'), 还有 O', 都是 son of 某某人的意思 (O' 其实是 grandson of )。McDonald 这个姓就类似于英语中的 Smithson, Johnson，从某个角度表示了这个家族的发展历史。&lt;br /&gt;
&lt;br /&gt;
我遇到过的例子有 McMaster, MacDonald, MacLeod, &lt;a href="http://en.wikipedia.org/wiki/O%27Brien_%28Nineteen_Eighty-Four%29"&gt;O'Brien&lt;/a&gt;。&lt;a href="http://www.google.com/search?q=Mac+mc+son"&gt;搜索一下&lt;/a&gt;，有更深入的解释。这几个姓貌似来源于苏格兰语或者爱尔兰语。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-4701078540769924926?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/5rlTq7FlaWE" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/4701078540769924926?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/4701078540769924926?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/03/what-does-mc-in-mcdonald-mean.html" title="What does the Mc in McDonald mean?" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;DUUEQnY_fSp7ImA9Wx9aEkk.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-6004142415226800256</id><published>2011-03-04T21:55:00.000+08:00</published><updated>2011-03-04T22:00:03.845+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-04T22:00:03.845+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="c" /><title>where are the functions defined?</title><content type="html">&lt;b&gt;0.&amp;nbsp; Token Concatenation&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
在 C 代码中，宏定义中可以进行"文本"层面上的变换，比如在 systemd 的链表实现 (类似 Linux kernel 的链表) 中有这样的用法,&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;&lt;span style="color: #004a43;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;define&lt;/span&gt;&lt;span style="color: #004a43;"&gt; LIST_FIELDS&lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;t&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt;&lt;span style="color: #004a43;"&gt;name&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                                             \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;t &lt;/span&gt;&lt;span style="color: #808030;"&gt;*&lt;/span&gt;&lt;span style="color: #004a43;"&gt;name&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;_next&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;*&lt;/span&gt;&lt;span style="color: #004a43;"&gt;name&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;_prev&lt;/span&gt;
&lt;/pre&gt;"##" 能完成所谓的 Token Concatenation, 具体解释看 &lt;a href="http://gcc.gnu.org/onlinedocs/cpp/Concatenation.html"&gt;gnu.org 的手册&lt;/a&gt;, 和&lt;a href="http://en.wikipedia.org/wiki/C_preprocessor#Token_concatenation"&gt;维基百科&lt;/a&gt;，简单的说，## 能把前后两个 token 连为一个。上边定义的 LIST_FIELDS 可以这样使用，&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;&lt;span style="color: maroon; font-weight: bold;"&gt;struct&lt;/span&gt; Job &lt;span style="color: purple;"&gt;{&lt;/span&gt;
        LIST_FIELDS&lt;span style="color: #808030;"&gt;(&lt;/span&gt;Job&lt;span style="color: #808030;"&gt;,&lt;/span&gt; transaction&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
        LIST_FIELDS&lt;span style="color: #808030;"&gt;(&lt;/span&gt;Job&lt;span style="color: #808030;"&gt;,&lt;/span&gt; run_queue&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
&lt;span style="color: purple;"&gt;}&lt;/span&gt;
&lt;/pre&gt;编译的时候就能扩展为&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;&lt;span style="color: maroon; font-weight: bold;"&gt;struct&lt;/span&gt; Job &lt;span style="color: purple;"&gt;{&lt;/span&gt;
        Job &lt;span style="color: #808030;"&gt;*&lt;/span&gt;transaction_next&lt;span style="color: #808030;"&gt;,&lt;/span&gt; &lt;span style="color: #808030;"&gt;*&lt;/span&gt;transaction_prev&lt;span style="color: purple;"&gt;;&lt;/span&gt;
        Job &lt;span style="color: #808030;"&gt;*&lt;/span&gt;run_queue_next&lt;span style="color: #808030;"&gt;,&lt;/span&gt; &lt;span style="color: #808030;"&gt;*&lt;/span&gt;run_queue_prev&lt;span style="color: purple;"&gt;;&lt;/span&gt;
&lt;span style="color: purple;"&gt;}&lt;/span&gt;
&lt;/pre&gt;这样确实很聪明，也很省事。但是如果你不熟悉这种用法，初读代码会一头雾水，因为遇到下边这样的代码时，根本找不到这些 _next 和 _prev 变量的定义，无论是用 cscope 还是 grep。&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;assert&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #808030;"&gt;!&lt;/span&gt;j&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;gt;&lt;/span&gt;transaction_next&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
assert&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #808030;"&gt;!&lt;/span&gt;j&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;gt;&lt;/span&gt;transaction_prev&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;1. 没有定义的 to_string 和 from_string 函数&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
最近看 systemd 代码，遇到了一个叫 log_target_from_string 的函数。某个头文件有它的声明，&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;LogTarget log_target_from_string&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: maroon; font-weight: bold;"&gt;const&lt;/span&gt; &lt;span style="color: maroon; font-weight: bold;"&gt;char&lt;/span&gt; &lt;span style="color: #808030;"&gt;*&lt;/span&gt;s&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;
&lt;/pre&gt;但是却找不到它的定义。最后发现是这样的，&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;&lt;span style="color: dimgrey;"&gt;/* src/log.c */&lt;/span&gt;

&lt;span style="color: maroon; font-weight: bold;"&gt;static&lt;/span&gt; &lt;span style="color: maroon; font-weight: bold;"&gt;const&lt;/span&gt; &lt;span style="color: maroon; font-weight: bold;"&gt;char&lt;/span&gt; &lt;span style="color: #808030;"&gt;*&lt;/span&gt;&lt;span style="color: maroon; font-weight: bold;"&gt;const&lt;/span&gt; log_target_table&lt;span style="color: #808030;"&gt;[&lt;/span&gt;&lt;span style="color: #808030;"&gt;]&lt;/span&gt; &lt;span style="color: #808030;"&gt;=&lt;/span&gt; &lt;span style="color: purple;"&gt;{&lt;/span&gt;
        &lt;span style="color: #808030;"&gt;[&lt;/span&gt;LOG_TARGET_CONSOLE&lt;span style="color: #808030;"&gt;]&lt;/span&gt; &lt;span style="color: #808030;"&gt;=&lt;/span&gt; &lt;span style="color: maroon;"&gt;"&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;console&lt;/span&gt;&lt;span style="color: maroon;"&gt;"&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt;
        &lt;span style="color: #808030;"&gt;[&lt;/span&gt;LOG_TARGET_SYSLOG&lt;span style="color: #808030;"&gt;]&lt;/span&gt; &lt;span style="color: #808030;"&gt;=&lt;/span&gt; &lt;span style="color: maroon;"&gt;"&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;syslog&lt;/span&gt;&lt;span style="color: maroon;"&gt;"&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt;
        &lt;span style="color: #808030;"&gt;[&lt;/span&gt;LOG_TARGET_KMSG&lt;span style="color: #808030;"&gt;]&lt;/span&gt; &lt;span style="color: #808030;"&gt;=&lt;/span&gt; &lt;span style="color: maroon;"&gt;"&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;kmsg&lt;/span&gt;&lt;span style="color: maroon;"&gt;"&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt;
        &lt;span style="color: #808030;"&gt;[&lt;/span&gt;LOG_TARGET_SYSLOG_OR_KMSG&lt;span style="color: #808030;"&gt;]&lt;/span&gt; &lt;span style="color: #808030;"&gt;=&lt;/span&gt; &lt;span style="color: maroon;"&gt;"&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;syslog-or-kmsg&lt;/span&gt;&lt;span style="color: maroon;"&gt;"&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt;
        &lt;span style="color: #808030;"&gt;[&lt;/span&gt;LOG_TARGET_NULL&lt;span style="color: #808030;"&gt;]&lt;/span&gt; &lt;span style="color: #808030;"&gt;=&lt;/span&gt; &lt;span style="color: maroon;"&gt;"&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;null&lt;/span&gt;&lt;span style="color: maroon;"&gt;"&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt;
        &lt;span style="color: #808030;"&gt;[&lt;/span&gt;LOG_TARGET_AUTO&lt;span style="color: #808030;"&gt;]&lt;/span&gt; &lt;span style="color: #808030;"&gt;=&lt;/span&gt; &lt;span style="color: maroon;"&gt;"&lt;/span&gt;&lt;span style="color: #0000e6;"&gt;auto&lt;/span&gt;&lt;span style="color: maroon;"&gt;"&lt;/span&gt;
&lt;span style="color: purple;"&gt;}&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;

DEFINE_STRING_TABLE_LOOKUP&lt;span style="color: #808030;"&gt;(&lt;/span&gt;log_target&lt;span style="color: #808030;"&gt;,&lt;/span&gt; LogTarget&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: purple;"&gt;;&lt;/span&gt;

&lt;span style="color: dimgrey;"&gt;/* src/util.h */&lt;/span&gt;

&lt;span style="color: #004a43;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;define&lt;/span&gt;&lt;span style="color: #004a43;"&gt; DEFINE_STRING_TABLE_LOOKUP&lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;name&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt;&lt;span style="color: #004a43;"&gt;type&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                           \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const char &lt;/span&gt;&lt;span style="color: #808030;"&gt;*&lt;/span&gt;&lt;span style="color: #004a43;"&gt;name&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;_to_string&lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;type i&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                          \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;if&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;i &lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #004a43;"&gt; 0 &lt;/span&gt;&lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #004a43;"&gt; i &lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #808030;"&gt;=&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;type&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt; ELEMENTSOF&lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;name&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;_table&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt;      \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return NULL&lt;/span&gt;&lt;span style="color: #808030;"&gt;;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                                    \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return name&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;_table&lt;/span&gt;&lt;span style="color: #808030;"&gt;[&lt;/span&gt;&lt;span style="color: #004a43;"&gt;i&lt;/span&gt;&lt;span style="color: #808030;"&gt;]&lt;/span&gt;&lt;span style="color: #808030;"&gt;;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                                 \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #808030;"&gt;}&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                                                               \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type name&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;_from_string&lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;const char &lt;/span&gt;&lt;span style="color: #808030;"&gt;*&lt;/span&gt;&lt;span style="color: #004a43;"&gt;s&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                        \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type i&lt;/span&gt;&lt;span style="color: #808030;"&gt;;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                                                 \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;unsigned u &lt;/span&gt;&lt;span style="color: #808030;"&gt;=&lt;/span&gt;&lt;span style="color: #004a43;"&gt; 0&lt;/span&gt;&lt;span style="color: #808030;"&gt;;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                                         \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assert&lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;s&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #808030;"&gt;;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                                              \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for &lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;i &lt;/span&gt;&lt;span style="color: #808030;"&gt;=&lt;/span&gt;&lt;span style="color: #004a43;"&gt; 0&lt;/span&gt;&lt;span style="color: #808030;"&gt;;&lt;/span&gt;&lt;span style="color: #004a43;"&gt; i &lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;type&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt;ELEMENTSOF&lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;name&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;_table&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #808030;"&gt;;&lt;/span&gt;&lt;span style="color: #004a43;"&gt; i&lt;/span&gt;&lt;span style="color: #808030;"&gt;+&lt;/span&gt;&lt;span style="color: #808030;"&gt;+&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt;    \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;if&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;name&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;_table&lt;/span&gt;&lt;span style="color: #808030;"&gt;[&lt;/span&gt;&lt;span style="color: #004a43;"&gt;i&lt;/span&gt;&lt;span style="color: #808030;"&gt;]&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                          \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;streq&lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;name&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;_table&lt;/span&gt;&lt;span style="color: #808030;"&gt;[&lt;/span&gt;&lt;span style="color: #004a43;"&gt;i&lt;/span&gt;&lt;span style="color: #808030;"&gt;]&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt;&lt;span style="color: #004a43;"&gt; s&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                  \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return i&lt;/span&gt;&lt;span style="color: #808030;"&gt;;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                               \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;if&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;safe_atou&lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;s&lt;/span&gt;&lt;span style="color: #808030;"&gt;,&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;u&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #808030;"&gt;=&lt;/span&gt;&lt;span style="color: #004a43;"&gt; 0 &lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                            \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;u &lt;/span&gt;&lt;span style="color: #808030;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #004a43;"&gt; ELEMENTSOF&lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;name&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #808030;"&gt;#&lt;/span&gt;&lt;span style="color: #004a43;"&gt;_table&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                       \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;type&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt; u&lt;/span&gt;&lt;span style="color: #808030;"&gt;;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                                \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &lt;/span&gt;&lt;span style="color: #808030;"&gt;(&lt;/span&gt;&lt;span style="color: #004a43;"&gt;type&lt;/span&gt;&lt;span style="color: #808030;"&gt;)&lt;/span&gt;&lt;span style="color: #004a43;"&gt; &lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #004a43;"&gt;1&lt;/span&gt;&lt;span style="color: #808030;"&gt;;&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                                       \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #808030;"&gt;}&lt;/span&gt;&lt;span style="color: #004a43;"&gt;                                                               \&lt;/span&gt;
&lt;span style="color: #004a43;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;struct __useless_struct_to_allow_trailing_semicolon__&lt;/span&gt;
&lt;/pre&gt;也就是说有一个通用的宏 DEFINE_STRING_TABLE_LOOKUP，它提供了 to_string 和 from_string 这两个函数的“模板”。&lt;br /&gt;
&lt;br /&gt;
systemd 需要进行很多的 enum 数值和对应的字符串之间的转换，这些对应关系都是定义在一个个的字符串数组中，比如上面的 log_target_table。转换操作其实很简单，无非就是在数组中进行查找，但是代码树里有很多这样的数组，也有很多的 enum 类型。如果要给每个数组都定义自己的 to_string 和 from_string 函数，那肯定是一大坨重复代码。&lt;br /&gt;
&lt;br /&gt;
使用 token concatenation 显然是一个很聪明的办法，达到的效果跟 C++ 的模板机制是类似的，能够大幅度地减少代码的重复。DRY! (C vs. C++... 不敢妄下评论，you be the judge)。&lt;br /&gt;
&lt;br /&gt;
(定义一个通用的查找函数也许是另一种办法)。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-6004142415226800256?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/ZoJqnId7vL8" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/6004142415226800256?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/6004142415226800256?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/03/where-are-functions-defined.html" title="where are the functions defined?" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;DUUGQXk8eSp7ImA9Wx9aEkk.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-1712783888705575391</id><published>2011-03-02T20:47:00.002+08:00</published><updated>2011-03-04T22:00:20.771+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-04T22:00:20.771+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><title>how gnome starts</title><content type="html">关于 Linux 的启动过程，网上有不少资料。&lt;a href="http://cromwell-intl.com/unix/linux-boot.html"&gt;比如这个&lt;/a&gt;，从按下开机键到创建 TTY 登录界面这个过程讲的很清楚。但是没有讲到这之后发生的故事。gdm 是怎么启动的？X server 又是怎么启动的？&lt;br /&gt;
&lt;br /&gt;
运行下 pstree，会发现这样一个进程树结构。&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;init&lt;span style="color: #808030;"&gt;-&lt;/span&gt;
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;gdm&lt;span style="color: #808030;"&gt;-&lt;/span&gt;binary&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;+&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;gdm&lt;span style="color: #808030;"&gt;-&lt;/span&gt;simple&lt;span style="color: #808030;"&gt;-&lt;/span&gt;slav&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;+&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;Xorg
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;gdm&lt;span style="color: #808030;"&gt;-&lt;/span&gt;session&lt;span style="color: #808030;"&gt;-&lt;/span&gt;wor&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;+&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;gnome&lt;span style="color: #808030;"&gt;-&lt;/span&gt;session&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;+&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;applet&lt;span style="color: #008c00;"&gt;.&lt;/span&gt;py
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;               &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;gdu&lt;span style="color: #808030;"&gt;-&lt;/span&gt;notificatio
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;               &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;gnome&lt;span style="color: #808030;"&gt;-&lt;/span&gt;panel&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;gnome&lt;span style="color: #808030;"&gt;-&lt;/span&gt;panel&lt;span style="color: #808030;"&gt;}&lt;/span&gt;
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;               &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;gnome&lt;span style="color: #808030;"&gt;-&lt;/span&gt;power&lt;span style="color: #808030;"&gt;-&lt;/span&gt;man&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;gnome&lt;span style="color: #808030;"&gt;-&lt;/span&gt;power&lt;span style="color: #808030;"&gt;-&lt;/span&gt;man&lt;span style="color: #808030;"&gt;}&lt;/span&gt;
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;               &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;gnome&lt;span style="color: #808030;"&gt;-&lt;/span&gt;volume&lt;span style="color: #808030;"&gt;-&lt;/span&gt;co
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;               &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;kerneloops&lt;span style="color: #808030;"&gt;-&lt;/span&gt;appl
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;               &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;metacity&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;metacity&lt;span style="color: #808030;"&gt;}&lt;/span&gt;
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;               &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;nautilus&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;2&lt;/span&gt;&lt;span style="color: #808030;"&gt;*&lt;/span&gt;&lt;span style="color: #808030;"&gt;[&lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;nautilus&lt;span style="color: #808030;"&gt;}&lt;/span&gt;&lt;span style="color: #808030;"&gt;]&lt;/span&gt;
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;               &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;nm&lt;span style="color: #808030;"&gt;-&lt;/span&gt;applet&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;nm&lt;span style="color: #808030;"&gt;-&lt;/span&gt;applet&lt;span style="color: #808030;"&gt;}&lt;/span&gt;
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;               &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;polkit&lt;span style="color: #808030;"&gt;-&lt;/span&gt;gnome&lt;span style="color: #808030;"&gt;-&lt;/span&gt;au&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;2&lt;/span&gt;&lt;span style="color: #808030;"&gt;*&lt;/span&gt;&lt;span style="color: #808030;"&gt;[&lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;polkit&lt;span style="color: #808030;"&gt;-&lt;/span&gt;gnome&lt;span style="color: #808030;"&gt;-&lt;/span&gt;au&lt;span style="color: #808030;"&gt;}&lt;/span&gt;&lt;span style="color: #808030;"&gt;]&lt;/span&gt;
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;               &lt;span style="color: #808030;"&gt;|&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;stardict&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;4&lt;/span&gt;&lt;span style="color: #808030;"&gt;*&lt;/span&gt;&lt;span style="color: #808030;"&gt;[&lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;stardict&lt;span style="color: #808030;"&gt;}&lt;/span&gt;&lt;span style="color: #808030;"&gt;]&lt;/span&gt;
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;               `&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;2&lt;/span&gt;&lt;span style="color: #808030;"&gt;*&lt;/span&gt;&lt;span style="color: #808030;"&gt;[&lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;gnome&lt;span style="color: #808030;"&gt;-&lt;/span&gt;session&lt;span style="color: #808030;"&gt;}&lt;/span&gt;&lt;span style="color: #808030;"&gt;]&lt;/span&gt;
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 `&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;gdm&lt;span style="color: #808030;"&gt;-&lt;/span&gt;session&lt;span style="color: #808030;"&gt;-&lt;/span&gt;wor&lt;span style="color: #808030;"&gt;}&lt;/span&gt;
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            &lt;span style="color: #808030;"&gt;|&lt;/span&gt;                 `&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;gdm&lt;span style="color: #808030;"&gt;-&lt;/span&gt;simple&lt;span style="color: #808030;"&gt;-&lt;/span&gt;slav&lt;span style="color: #808030;"&gt;}&lt;/span&gt;
     &lt;span style="color: #808030;"&gt;|&lt;/span&gt;            `&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;{&lt;/span&gt;gdm&lt;span style="color: #808030;"&gt;-&lt;/span&gt;binary&lt;span style="color: #808030;"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;br /&gt;
这些是如何发生的？&lt;br /&gt;
&lt;br /&gt;
下边是一个基于 Foresight Linux 的很简单的讲解。但是应该也适用于所有建立在传统的 sysvinit 之上的 Linux 发行版。而至于 upstart 和 systemd 等等就不适用了。&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;1. init -&amp;gt; /etc/X11/prefdm&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
我们都知道 kernel 在启动之后，会执行 init 程序。而 init 的行为是由 /etc/inittab 定义的。&lt;br /&gt;
&lt;br /&gt;
我的系统上 inittab 有这样一行:&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;$ tail &lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;1&lt;/span&gt; &lt;span style="color: #808030;"&gt;/&lt;/span&gt;etc&lt;span style="color: #808030;"&gt;/&lt;/span&gt;inittab 
x&lt;span style="color: #808030;"&gt;:&lt;/span&gt;&lt;span style="color: #008c00;"&gt;5&lt;/span&gt;&lt;span style="color: #808030;"&gt;:&lt;/span&gt;respawn&lt;span style="color: #808030;"&gt;:&lt;/span&gt;&lt;span style="color: #808030;"&gt;/&lt;/span&gt;etc&lt;span style="color: #808030;"&gt;/&lt;/span&gt;X11&lt;span style="color: #808030;"&gt;/&lt;/span&gt;prefdm &lt;span style="color: #808030;"&gt;-&lt;/span&gt;nodaemon
&lt;/pre&gt;也就是说在进入 runlevel 5 的时候，init 会调用 &lt;span style="color: #808030;"&gt;/&lt;/span&gt;etc&lt;span style="color: #808030;"&gt;/&lt;/span&gt;X11&lt;span style="color: #808030;"&gt;/&lt;/span&gt;prefdm。这是 X11 目录下的一个文件，我们应该能大体猜出它的用处。&lt;br /&gt;
&lt;br /&gt;
小插曲: 这个文件其实是 initscripts 提供的，&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;$ conary q &lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;path &lt;span style="color: #808030;"&gt;/&lt;/span&gt;etc&lt;span style="color: #808030;"&gt;/&lt;/span&gt;X11&lt;span style="color: #808030;"&gt;/&lt;/span&gt;prefdm
initscripts&lt;span style="color: #808030;"&gt;:&lt;/span&gt;runtime&lt;span style="color: #808030;"&gt;=&lt;/span&gt;foresight&lt;span style="color: #008c00;"&gt;.&lt;/span&gt;rpath&lt;span style="color: #008c00;"&gt;.&lt;/span&gt;org@fl&lt;span style="color: #808030;"&gt;:&lt;/span&gt;&lt;span style="color: #008c00;"&gt;2&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;qa&lt;span style="color: #808030;"&gt;/&lt;/span&gt;&lt;span style="color: #008c00;"&gt;9.12&lt;/span&gt;&lt;span style="color: #008c00;"&gt;.1&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;0.3&lt;/span&gt;&lt;span style="color: #808030;"&gt;-&lt;/span&gt;&lt;span style="color: #008c00;"&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;br /&gt;
2. &lt;b&gt;/etc/X11/prefdm -&amp;gt; gdm&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color: #808030;"&gt;/&lt;/span&gt;etc&lt;span style="color: #808030;"&gt;/&lt;/span&gt;X11&lt;span style="color: #808030;"&gt;/&lt;/span&gt;prefdm 是个很短的 shell 脚本。作用很简单，它会依次尝试运行 gdm, kdm 等等。对 GNOME 来说就是相当于 exec gdm。这样 gdm 进程就取代了 prefdm。&lt;br /&gt;
&lt;br /&gt;
3. &lt;b&gt;gdm -&amp;gt; Xorg&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
你可能发现了，直到现在 X server 还没有启动呢。上边的进程树中也体现出来了，gdm 是 init 的子进程，而 Xorg 是 gdm 的子进程。&lt;br /&gt;
&lt;br /&gt;
gdm 的全称是 GNOME Display Manager，是 X display manager 的一种。维基百科说了，&lt;a href="http://en.wikipedia.org/wiki/GNOME_Display_Manager"&gt;gdm&lt;/a&gt; 是对默认的 xdm 的一个更加易用的替换。&lt;br /&gt;
&lt;br /&gt;
那么什么是 X display manager？还看&lt;a href="http://en.wikipedia.org/wiki/X_display_manager_%28program_type%29"&gt;维基百科&lt;/a&gt;，&lt;br /&gt;
&lt;blockquote&gt;When the display manager runs on the user's computer, it starts the X server before presenting the user the login screen&lt;/blockquote&gt;也就是说，gdm 会首先启动 X server (比如在 tty7 上)，然后把登录界面显示出来。这样用户就可以登录了。&lt;br /&gt;
&lt;br /&gt;
其实就是这么简单。再输入密码，gnome-session, gnome-panel 等等就会启动，你就能进入到你的桌面了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-1712783888705575391?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/2kB7KrycPXg" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/1712783888705575391?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/1712783888705575391?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/03/how-gnome-starts.html" title="how gnome starts" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;DkcNRnY9cSp7ImA9Wx9UEUo.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-3909808338988914945</id><published>2011-02-08T22:02:00.004+08:00</published><updated>2011-02-08T22:08:17.869+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-08T22:08:17.869+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="foresight" /><category scheme="http://www.blogger.com/atom/ns#" term="conary" /><title>package testing made easy by conary rollback</title><content type="html">Some time ago I came into a bug of foresight, &lt;a href="http://issues.foresightlinux.org/jira/browse/FL-2639"&gt;FL-2639 - fails to boot due to libata-migrate&lt;/a&gt;. Then our lead developer António committed &lt;a href="http://lists.rpath.org/pipermail/foresight-commits/2011-February/046257.html"&gt;an updated recipe&lt;/a&gt;. But before new packages are made, I was asked to build the recipe and test it locally.&lt;br /&gt;
&lt;br /&gt;
So I checked out the recipe, and 'cooked' it on my system.&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_I3CMVTMGpic/TVFJJRRD5vI/AAAAAAAAALs/GiZzEgL-XYs/s1600/Screenshot.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="275" src="http://3.bp.blogspot.com/_I3CMVTMGpic/TVFJJRRD5vI/AAAAAAAAALs/GiZzEgL-XYs/s400/Screenshot.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;cvc cook mkinitrd.recipe&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
The package was built and I installed it.&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_I3CMVTMGpic/TVFJwA_vmtI/AAAAAAAAALw/TvFGAN9p14U/s1600/Screenshot-1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="137" src="http://1.bp.blogspot.com/_I3CMVTMGpic/TVFJwA_vmtI/AAAAAAAAALw/TvFGAN9p14U/s400/Screenshot-1.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;sudo conary update mkinitrd-6.0.93.ccs&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
But something seemed wrong, as you might guess from the libata-migrate warnings in the above screenshot.&lt;br /&gt;
&lt;br /&gt;
So I asked António and confirmed the problem.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_I3CMVTMGpic/TVFKLY9O-MI/AAAAAAAAAL4/8UICt08_Gnw/s1600/Screenshot-3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="35" src="http://3.bp.blogspot.com/_I3CMVTMGpic/TVFKLY9O-MI/AAAAAAAAAL4/8UICt08_Gnw/s400/Screenshot-3.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
I didn't panic. As António said, I ran a single command and brought my system back to safety :)&lt;br /&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_I3CMVTMGpic/TVFJ8QHgZQI/AAAAAAAAAL0/jOm-7ZokWTc/s1600/Screenshot-2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="247" src="http://3.bp.blogspot.com/_I3CMVTMGpic/TVFJ8QHgZQI/AAAAAAAAAL0/jOm-7ZokWTc/s400/Screenshot-2.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;sudo conary rollback 1&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
That's a typical scenario during foresight development, and part of what makes it a fun to work with conary.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-3909808338988914945?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/BEqmFCvr3SI" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/3909808338988914945?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/3909808338988914945?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/02/package-testing-made-easy-by-conary.html" title="package testing made easy by conary rollback" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_I3CMVTMGpic/TVFJJRRD5vI/AAAAAAAAALs/GiZzEgL-XYs/s72-c/Screenshot.png" height="72" width="72" /></entry><entry gd:etag="W/&quot;C0cDSH0zeSp7ImA9Wx9VF0k.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-2031830371513322348</id><published>2011-02-02T23:30:00.003+08:00</published><updated>2011-02-03T21:51:19.381+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-03T21:51:19.381+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="foresight" /><title>foresight 2.5.0 ALPHA 2 released</title><content type="html">Og Maciel 刚刚发布了 &lt;a href="http://www.foresightlinux.org/release/foresight-linux-2-5-0-alpha-2-gnome-edition-release-notes/"&gt;Foresight Linux 2.5.0 ALPHA 2&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Foresight 经过了一段很艰难的岁月，但是我们撑过来了 :) ALPHA1 发布之后，还是吸引了相当多的关注。根据 DistroWatch, &lt;a href="http://distrowatch.com/stats.php?section=popularity"&gt;Foresight 的关注度&lt;/a&gt;从 185 位, 升到 147, 又升到 115, 然后又升到了 47。&lt;br /&gt;
&lt;br /&gt;
ALPHA2 下载链接，&lt;br /&gt;
&lt;pre&gt;* Foresight Linux GNOME Edition 2.5.0 x86:
    URL: &lt;a href="https://www.rpath.org/images/foresight/27224/foresight-2.4.99+alpha2+2011.01.31-x86-dvd1.iso"&gt;https://www.rpath.org/images/foresight/27224/foresight-2.4.99+alpha2+2011.01.31-x86-dvd1.iso&lt;/a&gt;
    Size: 1.60 GB
    SHA1: 9068e94a0c6552409ae46893e2d32bbfedc0b442

* Foresight Linux GNOME Edition 2.5.0 x86_64:

    URL: &lt;a href="https://www.rpath.org/images/foresight/27223/foresight-2.4.99+alpha2+2011.01.31-x86_64-dvd1.iso"&gt;https://www.rpath.org/images/foresight/27223/foresight-2.4.99+alpha2+2011.01.31-x86_64-dvd1.iso&lt;/a&gt;
    Size: 1.78 GB
    SHA1: f8fe9c020f97b114d9f543f427caa498c0f407ac
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-2031830371513322348?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/3fhxk9pztVs" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2031830371513322348?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2031830371513322348?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/02/foresight-250-alpha-2-released.html" title="foresight 2.5.0 ALPHA 2 released" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;CEcAQHc7eSp7ImA9Wx9aFEw.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-7500435256010582854</id><published>2011-02-02T15:03:00.003+08:00</published><updated>2011-03-06T19:47:21.901+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-06T19:47:21.901+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="foresight" /><category scheme="http://www.blogger.com/atom/ns#" term="conary" /><title>using conary api</title><content type="html">Conary has a &lt;a href="http://cvs.rpath.com/conary-docs/"&gt;public API&lt;/a&gt;, through which you can have access to the packages on your system. Here is some quick examples.&lt;br /&gt;
&lt;br /&gt;
1. Query packages installed locally, (equivalent of 'conary query')&lt;br /&gt;
&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;span style="font-family: monospace;"&gt;
&lt;span style="color: #af5f00;"&gt;1 &lt;/span&gt;&lt;span style="color: #0000c0;"&gt;# test1.py&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt;2 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; pprint
&lt;span style="color: #af5f00;"&gt;3 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt;4 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;from&lt;/span&gt; conary.conaryclient &lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; ConaryClient
&lt;span style="color: #af5f00;"&gt;5 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;from&lt;/span&gt; conary.conarycfg &lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; ConaryConfiguration
&lt;span style="color: #af5f00;"&gt;6 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt;7 &lt;/span&gt;c = ConaryClient(ConaryConfiguration())
&lt;span style="color: #af5f00;"&gt;8 &lt;/span&gt;troves = c.db.findTroves(&lt;span style="color: teal;"&gt;None&lt;/span&gt;, [(&lt;span style="color: #c00000;"&gt;'dbus'&lt;/span&gt;, &lt;span style="color: teal;"&gt;None&lt;/span&gt;, &lt;span style="color: teal;"&gt;None&lt;/span&gt;)])
&lt;span style="color: #af5f00;"&gt;9 &lt;/span&gt;pprint.pprint(troves)
&lt;/span&gt;&lt;/pre&gt;&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;span style="font-family: monospace;"&gt;
$ python test1.py 
{('dbus', None, None): [('dbus',
                         VFS('/foresight.rpath.org@fl:devel//2-qa/1.4.0-0.3-1'),
                         Flavor('is: x86')),
                        ('dbus',
                         VFS('/foresight.rpath.org@fl:devel//2-qa/1.4.0-0.3-1'),
                         Flavor('is: x86_64'))]}
$ conary q dbus
dbus=foresight.rpath.org@fl:2-qa/1.4.0-0.3-1[is: x86]
dbus=foresight.rpath.org@fl:2-qa/1.4.0-0.3-1[is: x86_64]
&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;
2. Query packages in the repository, (equivalent of 'conary repoquery')&lt;br /&gt;
&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;span style="font-family: monospace;"&gt;
&lt;span style="color: #af5f00;"&gt; 1 &lt;/span&gt;&lt;span style="color: #0000c0;"&gt;# test2.py&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 2 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; pprint
&lt;span style="color: #af5f00;"&gt; 3 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 4 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;from&lt;/span&gt; conary.conaryclient &lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; ConaryClient
&lt;span style="color: #af5f00;"&gt; 5 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;from&lt;/span&gt; conary.conarycfg &lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; ConaryConfiguration
&lt;span style="color: #af5f00;"&gt; 6 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 7 &lt;/span&gt;cfg = ConaryConfiguration(readConfigFiles=&lt;span style="color: teal;"&gt;True&lt;/span&gt;)
&lt;span style="color: #af5f00;"&gt; 8 &lt;/span&gt;c = ConaryClient(cfg)
&lt;span style="color: #af5f00;"&gt; 9 &lt;/span&gt;troves = c.repos.findTroves(cfg.installLabelPath, [(&lt;span style="color: #c00000;"&gt;'dbus'&lt;/span&gt;, &lt;span style="color: teal;"&gt;None&lt;/span&gt;, &lt;span style="color: teal;"&gt;None&lt;/span&gt;)])
&lt;span style="color: #af5f00;"&gt;10 &lt;/span&gt;pprint.pprint(troves)
&lt;/span&gt;&lt;/pre&gt;&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;span style="font-family: monospace;"&gt;
$ python test2.py
{('dbus', None, None): [('dbus',
                         VFS('/foresight.rpath.org@fl:devel//2-qa/1.4.0-0.3-1'),
                         Flavor('is: x86')),
                        ('dbus',
                         VFS('/foresight.rpath.org@fl:devel//2-qa/1.4.0-0.3-1'),
                         Flavor('is: x86_64'))]}
&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;
3. List files of a package, (equivalent of 'conary q --ls')&lt;br /&gt;
&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;span style="font-family: monospace;"&gt;
&lt;span style="color: #af5f00;"&gt; 1 &lt;/span&gt;&lt;span style="color: #0000c0;"&gt;# test3.py&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 2 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 3 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;from&lt;/span&gt; conary.conaryclient &lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; ConaryClient
&lt;span style="color: #af5f00;"&gt; 4 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;from&lt;/span&gt; conary.conarycfg &lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; ConaryConfiguration
&lt;span style="color: #af5f00;"&gt; 5 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 6 &lt;/span&gt;c = ConaryClient(ConaryConfiguration())
&lt;span style="color: #af5f00;"&gt; 7 &lt;/span&gt;n, v, f = c.db.findTrove(&lt;span style="color: teal;"&gt;None&lt;/span&gt;, (&lt;span style="color: #c00000;"&gt;'m4:doc'&lt;/span&gt;, &lt;span style="color: teal;"&gt;None&lt;/span&gt;, &lt;span style="color: teal;"&gt;None&lt;/span&gt;))[&lt;span style="color: #c00000;"&gt;0&lt;/span&gt;]
&lt;span style="color: #af5f00;"&gt; 8 &lt;/span&gt;trove = c.db.getTrove(n, v, f, withFiles=&lt;span style="color: teal;"&gt;True&lt;/span&gt;)
&lt;span style="color: #af5f00;"&gt; 9 &lt;/span&gt;&lt;span style="color: #af5f00;"&gt;for&lt;/span&gt; (pathId, path, fileId, version) &lt;span style="color: #af5f00;"&gt;in&lt;/span&gt; trove.iterFileList():
&lt;span style="color: #af5f00;"&gt;10 &lt;/span&gt;    &lt;span style="color: teal;"&gt;print&lt;/span&gt; path
&lt;/span&gt;&lt;/pre&gt;&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;span style="font-family: monospace;"&gt;
$ python test3.py 
/usr/share/info/m4.info.gz
/usr/share/man/man1/m4.1.gz
&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;
Note that the trove you use for iterFileList() "will have to be a trove that has files -- a component or fileset, but not a package or a group". ('Trove' is a general name for package/component/group).&lt;br /&gt;
&lt;br /&gt;
And there is also a second approach,&lt;br /&gt;
&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;span style="font-family: monospace;"&gt;
&lt;span style="color: #af5f00;"&gt;1 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;from&lt;/span&gt; conary.conaryclient &lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; ConaryClient
&lt;span style="color: #af5f00;"&gt;2 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;from&lt;/span&gt; conary.conarycfg &lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; ConaryConfiguration
&lt;span style="color: #af5f00;"&gt;3 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt;4 &lt;/span&gt;c = ConaryClient(ConaryConfiguration())
&lt;span style="color: #af5f00;"&gt;5 &lt;/span&gt;n, v, f = c.db.findTrove(&lt;span style="color: teal;"&gt;None&lt;/span&gt;, (&lt;span style="color: #c00000;"&gt;'m4:doc'&lt;/span&gt;, &lt;span style="color: teal;"&gt;None&lt;/span&gt;, &lt;span style="color: teal;"&gt;None&lt;/span&gt;))[&lt;span style="color: #c00000;"&gt;0&lt;/span&gt;]
&lt;span style="color: #af5f00;"&gt;6 &lt;/span&gt;&lt;span style="color: teal;"&gt;iter&lt;/span&gt; = c.db.iterFilesInTrove(n, v, f, withFiles=&lt;span style="color: teal;"&gt;True&lt;/span&gt;, capsules=&lt;span style="color: teal;"&gt;False&lt;/span&gt;)
&lt;span style="color: #af5f00;"&gt;7 &lt;/span&gt;&lt;span style="color: #af5f00;"&gt;for&lt;/span&gt; (pathId, path, fileId, version, filename) &lt;span style="color: #af5f00;"&gt;in&lt;/span&gt; &lt;span style="color: teal;"&gt;iter&lt;/span&gt;:
&lt;span style="color: #af5f00;"&gt;8 &lt;/span&gt;    &lt;span style="color: teal;"&gt;print&lt;/span&gt; path
&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;
4. List components of a package, (equivalent of 'conary q --troves' or 'conary q --all-troves'):&lt;br /&gt;
&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;span style="font-family: monospace;"&gt;
&lt;span style="color: #af5f00;"&gt; 1 &lt;/span&gt;&lt;span style="color: #0000c0;"&gt;# test4.py&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 2 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 3 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;from&lt;/span&gt; conary.conaryclient &lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; ConaryClient
&lt;span style="color: #af5f00;"&gt; 4 &lt;/span&gt;&lt;span style="color: #c000c0;"&gt;from&lt;/span&gt; conary.conarycfg &lt;span style="color: #c000c0;"&gt;import&lt;/span&gt; ConaryConfiguration
&lt;span style="color: #af5f00;"&gt; 5 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 6 &lt;/span&gt;c = ConaryClient(ConaryConfiguration())
&lt;span style="color: #af5f00;"&gt; 7 &lt;/span&gt;n, v, f = c.db.findTrove(&lt;span style="color: teal;"&gt;None&lt;/span&gt;, (&lt;span style="color: #c00000;"&gt;'kernel'&lt;/span&gt;, &lt;span style="color: teal;"&gt;None&lt;/span&gt;, &lt;span style="color: teal;"&gt;None&lt;/span&gt;))[&lt;span style="color: #c00000;"&gt;0&lt;/span&gt;]
&lt;span style="color: #af5f00;"&gt; 8 &lt;/span&gt;trove = c.db.getTrove(n, v, f)
&lt;span style="color: #af5f00;"&gt; 9 &lt;/span&gt;components = trove.iterTroveList(strongRefs=&lt;span style="color: teal;"&gt;True&lt;/span&gt;)
&lt;span style="color: #af5f00;"&gt;10 &lt;/span&gt;&lt;span style="color: #af5f00;"&gt;for&lt;/span&gt; (n, v, f) &lt;span style="color: #af5f00;"&gt;in&lt;/span&gt; components:
&lt;span style="color: #af5f00;"&gt;11 &lt;/span&gt;    &lt;span style="color: teal;"&gt;print&lt;/span&gt; &lt;span style="color: #c00000;"&gt;"%s %s %s - %s"&lt;/span&gt; % (n, v, f,
&lt;span style="color: #af5f00;"&gt;12 &lt;/span&gt;            &lt;span style="color: #c00000;"&gt;"Installed"&lt;/span&gt; &lt;span style="color: #af5f00;"&gt;if&lt;/span&gt; c.db.hasTrove(n, v, f) &lt;span style="color: #af5f00;"&gt;else&lt;/span&gt; &lt;span style="color: #c00000;"&gt;"Not Installed"&lt;/span&gt;)
&lt;/span&gt;&lt;/pre&gt;&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;span style="font-family: monospace;"&gt;
$ python test4.py 
kernel:runtime /foresight.rpath.org@fl:2-qa-kernel/2.6.35.10-5-1 ~kernel.debugdata,~!xen is: x86_64 - Installed
kernel:vmware /foresight.rpath.org@fl:2-qa-kernel/2.6.35.10-5-1 ~kernel.debugdata,~!xen is: x86_64 - Installed
kernel:debuginfo /foresight.rpath.org@fl:2-qa-kernel/2.6.35.10-5-1 ~kernel.debugdata,~!xen is: x86_64 - Not Installed
kernel:build-tree /foresight.rpath.org@fl:2-qa-kernel/2.6.35.10-5-1 ~kernel.debugdata,~!xen is: x86_64 - Not Installed
kernel:configs /foresight.rpath.org@fl:2-qa-kernel/2.6.35.10-5-1 ~kernel.debugdata,~!xen is: x86_64 - Installed
&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;
That's it, some dirty examples and I don't know if it's the recommended way of doing things. And not all functions used above are official public APIs (now I'm using conary-2.2.9 and python-2.6.6). So take care, and better to install &lt;a href="http://pypi.python.org/pypi/pycscope"&gt;pycscope&lt;/a&gt; and poke around &lt;a href="https://bitbucket.org/rpathsync/conary"&gt;the source code&lt;/a&gt; yourself:)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-7500435256010582854?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/Adz9ln6Ap-Y" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/7500435256010582854?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/7500435256010582854?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2011/02/using-conary-api.html" title="using conary api" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;DEECQno7fip7ImA9Wx9XGEU.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-1308362023664441823</id><published>2010-12-23T19:54:00.001+08:00</published><updated>2011-01-13T10:44:23.406+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-13T10:44:23.406+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="systemd" /><category scheme="http://www.blogger.com/atom/ns#" term="foresight" /><category scheme="http://www.blogger.com/atom/ns#" term="conary" /><title>explanation of a systemd.recipe</title><content type="html">I have been wanting to write something about packaging for conary. So here is an line-by-line explanation of the systemd recipe that I made for Foresight Linux.&lt;br /&gt;
&lt;br /&gt;
systemd is still under heavy development and my package is far from perfection, so this article is just to show you a typical conary recipe. It's not meant to be a packaging guide for systemd and the recipe is subject to change.&lt;br /&gt;
&lt;br /&gt;
------------------&lt;br /&gt;
&lt;br /&gt;
First let's see how it looks like.&lt;br /&gt;
&lt;pre style="background: none repeat scroll 0% 0% rgb(255, 255, 255); color: black;"&gt;&lt;span style="font-family: monospace;"&gt;&lt;span style="color: #af5f00;"&gt;  1 &lt;/span&gt;&lt;span style="color: #af5f00;"&gt;class&lt;/span&gt; &lt;span style="color: teal;"&gt;Systemd&lt;/span&gt;(AutoPackageRecipe):
&lt;span style="color: #af5f00;"&gt;  2 &lt;/span&gt;    &lt;span style="color: #c000c0;"&gt;name&lt;/span&gt; = '&lt;span style="color: #c00000;"&gt;systemd&lt;/span&gt;'
&lt;span style="color: #af5f00;"&gt;  3 &lt;/span&gt;    &lt;span style="color: #c000c0;"&gt;version&lt;/span&gt; = '&lt;span style="color: #c00000;"&gt;15&lt;/span&gt;'
&lt;span style="color: #af5f00;"&gt;  4 &lt;/span&gt; 
&lt;span style="color: #af5f00;"&gt;  5 &lt;/span&gt;    &lt;span style="color: #c000c0;"&gt;buildRequires&lt;/span&gt; = [
&lt;span style="color: #af5f00;"&gt;  6 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# for autoreconf&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt;  7 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;autoconf:runtime&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt;  8 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;automake:runtime&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt;  9 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 10 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;audit:devel&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 11 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;dbus:devel&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 12 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;libcap:devel&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 13 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;libxslt:runtime&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 14 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;m4:runtime&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 15 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;pam:devel&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 16 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;pkgconfig:devel&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 17 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;tcp_wrappers:devel&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 18 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;udev:devel&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 19 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;vala:runtime&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 20 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 21 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# for gtk support&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 22 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;dbus-glib:devel&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 23 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;gtk:devel&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 24 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;libnotify:devel&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 25 &lt;/span&gt;        ]
&lt;span style="color: #af5f00;"&gt; 26 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 27 &lt;/span&gt;    &lt;span style="color: #0000c0;"&gt;# &lt;/span&gt;&lt;span style="background-color: yellow;"&gt;&lt;span style="color: black;"&gt;XXX&lt;/span&gt;&lt;/span&gt;&lt;span style="color: #0000c0;"&gt; our cryptsetup may be too old and doesn't provide libcryptsetup.pc&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 28 &lt;/span&gt; 
&lt;span style="color: #af5f00;"&gt; 29 &lt;/span&gt;    extraConfig = (
&lt;span style="color: #af5f00;"&gt; 30 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;--with-distro=foresight &lt;/span&gt;'
&lt;span style="color: #af5f00;"&gt; 31 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;--with-rootdir= &lt;/span&gt;'
&lt;span style="color: #af5f00;"&gt; 32 &lt;/span&gt;        )
&lt;span style="color: #af5f00;"&gt; 33 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 34 &lt;/span&gt;    patches = [
&lt;span style="color: #af5f00;"&gt; 35 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# backported from upstream, for vala and libnotify version check&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 36 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;0001-gnome-ask-password-agent-also-support-libnotify-0.7-.patch&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 37 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;0002-Ensure-LIBNOTIFY07-conditional-is-always-set.patch&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 38 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# patches for porting to foresight&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 39 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;foresight-linux-port.patch&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 40 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;foresight-units.patch&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 41 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# need to update util-linux (&amp;gt;2.18) to have 'fsck -l'&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 42 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;foresight-workaround-old-fsck.patch&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 43 &lt;/span&gt;        ]
&lt;span style="color: #af5f00;"&gt; 44 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 45 &lt;/span&gt;    extraSources = [
&lt;span style="color: #af5f00;"&gt; 46 &lt;/span&gt;        '&lt;span style="color: #c00000;"&gt;console.conf&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 47 &lt;/span&gt;        ]
&lt;span style="color: #af5f00;"&gt; 48 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 49 &lt;/span&gt;    &lt;span style="color: #af5f00;"&gt;def&lt;/span&gt; &lt;span style="color: teal;"&gt;unpack&lt;/span&gt;(r):
&lt;span style="color: #af5f00;"&gt; 50 &lt;/span&gt;        r.&lt;span style="color: #af5f00;"&gt;addArchive&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;&lt;a href="http://www.freedesktop.org/software/systemd/"&gt;http://www.freedesktop.org/software/systemd/&lt;/a&gt;&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 51 &lt;/span&gt;        &lt;span style="color: #af5f00;"&gt;for&lt;/span&gt; patch &lt;span style="color: #af5f00;"&gt;in&lt;/span&gt; r.patches:
&lt;span style="color: #af5f00;"&gt; 52 &lt;/span&gt;            r.&lt;span style="color: #af5f00;"&gt;addPatch&lt;/span&gt;(patch)
&lt;span style="color: #af5f00;"&gt; 53 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 54 &lt;/span&gt;        &lt;span style="color: #af5f00;"&gt;for&lt;/span&gt; source &lt;span style="color: #af5f00;"&gt;in&lt;/span&gt; r.extraSources:
&lt;span style="color: #af5f00;"&gt; 55 &lt;/span&gt;            r.&lt;span style="color: #af5f00;"&gt;addSource&lt;/span&gt;(source)
&lt;span style="color: #af5f00;"&gt; 56 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 57 &lt;/span&gt;    &lt;span style="color: #af5f00;"&gt;def&lt;/span&gt; &lt;span style="color: teal;"&gt;configure&lt;/span&gt;(r):
&lt;span style="color: #af5f00;"&gt; 58 &lt;/span&gt;        r.&lt;span style="color: teal;"&gt;Run&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;autoreconf&lt;/span&gt;') &lt;span style="color: #0000c0;"&gt;# &lt;/span&gt;&lt;span style="background-color: yellow;"&gt;&lt;span style="color: black;"&gt;XXX&lt;/span&gt;&lt;/span&gt;&lt;span style="color: #0000c0;"&gt; is autoreconf right?&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 59 &lt;/span&gt;        r.&lt;span style="color: teal;"&gt;Configure&lt;/span&gt;(r.extraConfig)
&lt;span style="color: #af5f00;"&gt; 60 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 61 &lt;/span&gt;    &lt;span style="color: #af5f00;"&gt;def&lt;/span&gt; &lt;span style="color: teal;"&gt;policy&lt;/span&gt;(r):
&lt;span style="color: #af5f00;"&gt; 62 &lt;/span&gt;        r.&lt;span style="color: teal;"&gt;Install&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;console.conf&lt;/span&gt;', '&lt;span style="color: #c000c0;"&gt;%(sysconfdir)s&lt;/span&gt;&lt;span style="color: #c00000;"&gt;/tmpfiles.d/console.conf&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 63 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 64 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# /etc/xdg/systemd/user points to /etc/systemd/user&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 65 &lt;/span&gt;        r.&lt;span style="color: green;"&gt;ExcludeDirectories&lt;/span&gt;(exceptions='&lt;span style="color: #c000c0;"&gt;%(sysconfdir)s&lt;/span&gt;&lt;span style="color: #c00000;"&gt;/systemd/user&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 66 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 67 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# The unit files (plain-text) are in /lib/systemd/system, so no need to fix&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 68 &lt;/span&gt;        r.&lt;span style="color: green;"&gt;FixupMultilibPaths&lt;/span&gt;(exceptions='&lt;span style="color: #c00000;"&gt;/lib/systemd/system/&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 69 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 70 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# warning: DanglingSymlinks: symlink /usr/share/systemd/user/bluetooth.target&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 71 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# points from package systemd:data to systemd:lib&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 72 &lt;/span&gt;        r.&lt;span style="color: green;"&gt;ComponentSpec&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;lib&lt;/span&gt;', '&lt;span style="color: #c000c0;"&gt;%(datadir)s&lt;/span&gt;&lt;span style="color: #c00000;"&gt;/systemd/user/.*.target&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 73 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 74 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# Create SysV compatibility symlinks. systemctl/systemd are smart&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 75 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# enough to detect in which way they are called.&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 76 &lt;/span&gt;        r.&lt;span style="color: teal;"&gt;Symlink&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;../bin/systemd&lt;/span&gt;', '&lt;span style="color: #c00000;"&gt;/sbin/init&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 77 &lt;/span&gt;        r.&lt;span style="color: teal;"&gt;Symlink&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;../bin/systemctl&lt;/span&gt;', '&lt;span style="color: #c00000;"&gt;/sbin/reboot&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 78 &lt;/span&gt;        r.&lt;span style="color: teal;"&gt;Symlink&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;../bin/systemctl&lt;/span&gt;', '&lt;span style="color: #c00000;"&gt;/sbin/halt&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 79 &lt;/span&gt;        r.&lt;span style="color: teal;"&gt;Symlink&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;../bin/systemctl&lt;/span&gt;', '&lt;span style="color: #c00000;"&gt;/sbin/poweroff&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 80 &lt;/span&gt;        r.&lt;span style="color: teal;"&gt;Symlink&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;../bin/systemctl&lt;/span&gt;', '&lt;span style="color: #c00000;"&gt;/sbin/shutdown&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 81 &lt;/span&gt;        r.&lt;span style="color: teal;"&gt;Symlink&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;../bin/systemctl&lt;/span&gt;', '&lt;span style="color: #c00000;"&gt;/sbin/telinit&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 82 &lt;/span&gt;        r.&lt;span style="color: teal;"&gt;Symlink&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;../bin/systemctl&lt;/span&gt;', '&lt;span style="color: #c00000;"&gt;/sbin/runlevel&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 83 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 84 &lt;/span&gt;        &lt;span style="color: #0000c0;"&gt;# Use graphical.target unconditionaly as default for now&lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 85 &lt;/span&gt;        r.&lt;span style="color: teal;"&gt;Symlink&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;/lib/systemd/system/graphical.target&lt;/span&gt;', '&lt;span style="color: #c00000;"&gt;/etc/systemd/system/default.target&lt;/span&gt;')
&lt;span style="color: #af5f00;"&gt; 86 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 87 &lt;/span&gt;        cmds = (
&lt;span style="color: #af5f00;"&gt; 88 &lt;/span&gt;            '&lt;span style="color: #c00000;"&gt;/sbin/halt&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 89 &lt;/span&gt;            '&lt;span style="color: #c00000;"&gt;/sbin/init&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 90 &lt;/span&gt;            '&lt;span style="color: #c00000;"&gt;/sbin/poweroff&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 91 &lt;/span&gt;            '&lt;span style="color: #c00000;"&gt;/sbin/reboot&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 92 &lt;/span&gt;            '&lt;span style="color: #c00000;"&gt;/sbin/runlevel&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 93 &lt;/span&gt;            '&lt;span style="color: #c00000;"&gt;/sbin/shutdown&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 94 &lt;/span&gt;            '&lt;span style="color: #c00000;"&gt;/sbin/telinit&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 95 &lt;/span&gt;            )
&lt;span style="color: #af5f00;"&gt; 96 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt; 97 &lt;/span&gt;        mans = (
&lt;span style="color: #af5f00;"&gt; 98 &lt;/span&gt;            '&lt;span style="color: #c000c0;"&gt;%(datadir)s&lt;/span&gt;&lt;span style="color: #c00000;"&gt;/man/man1/init.1.*&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt; 99 &lt;/span&gt;            '&lt;span style="color: #c000c0;"&gt;%(datadir)s&lt;/span&gt;&lt;span style="color: #c00000;"&gt;/man/man8/halt.8.*&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt;100 &lt;/span&gt;            '&lt;span style="color: #c000c0;"&gt;%(datadir)s&lt;/span&gt;&lt;span style="color: #c00000;"&gt;/man/man8/poweroff.8.*&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt;101 &lt;/span&gt;            '&lt;span style="color: #c000c0;"&gt;%(datadir)s&lt;/span&gt;&lt;span style="color: #c00000;"&gt;/man/man8/reboot.8.*&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt;102 &lt;/span&gt;            '&lt;span style="color: #c000c0;"&gt;%(datadir)s&lt;/span&gt;&lt;span style="color: #c00000;"&gt;/man/man8/runlevel.8.*&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt;103 &lt;/span&gt;            '&lt;span style="color: #c000c0;"&gt;%(datadir)s&lt;/span&gt;&lt;span style="color: #c00000;"&gt;/man/man8/shutdown.8.*&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt;104 &lt;/span&gt;            '&lt;span style="color: #c000c0;"&gt;%(datadir)s&lt;/span&gt;&lt;span style="color: #c00000;"&gt;/man/man8/telinit.8.*&lt;/span&gt;',
&lt;span style="color: #af5f00;"&gt;105 &lt;/span&gt;            )
&lt;span style="color: #af5f00;"&gt;106 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt;107 &lt;/span&gt;        &lt;span style="color: #af5f00;"&gt;for&lt;/span&gt; f &lt;span style="color: #af5f00;"&gt;in&lt;/span&gt; cmds:
&lt;span style="color: #af5f00;"&gt;108 &lt;/span&gt;            r.&lt;span style="color: green;"&gt;DanglingSymlinks&lt;/span&gt;(exceptions=f)
&lt;span style="color: #af5f00;"&gt;109 &lt;/span&gt;
&lt;span style="color: #af5f00;"&gt;110 &lt;/span&gt;        &lt;span style="color: #af5f00;"&gt;for&lt;/span&gt; f &lt;span style="color: #af5f00;"&gt;in&lt;/span&gt; cmds + mans:
&lt;span style="color: #af5f00;"&gt;111 &lt;/span&gt;            r.&lt;span style="color: green;"&gt;PackageSpec&lt;/span&gt;('&lt;span style="color: #c00000;"&gt;systemd-sysvinit&lt;/span&gt;', f)&lt;/span&gt;&lt;/pre&gt;------------------&lt;br /&gt;
&lt;br /&gt;
Now let's break the recipe down into pieces.&lt;br /&gt;
&lt;br /&gt;
1. First of all, the recipe is called systemd.recipe and named after the package.&lt;br /&gt;
&lt;br /&gt;
2. Line 1&lt;br /&gt;
&lt;pre&gt;&lt;font color="#af5f00"&gt;class&lt;/font&gt; &lt;font color="#008080"&gt;Systemd&lt;/font&gt;(AutoPackageRecipe):&lt;/pre&gt;Most recipes get started like this. Remember that conary recipes are pure Python code. So here it's a Python "class" that's being defined. Its name is "Systemd" and it is inheriting from one super-class called "AutoPackageRecipe".&lt;br /&gt;
&lt;br /&gt;
The class name is in CamelCase and derived from the package name. Conary will do the transformation for you if the recipe is created using a template:&lt;br /&gt;
&lt;pre&gt;cvc newpkg systemd --template foresight&lt;/pre&gt;The "foresight" template (/etc/conary/recipeTemplates/foresight) is defined as:&lt;br /&gt;
&lt;pre&gt;class %(className)s(AutoPackageRecipe):&lt;/pre&gt;"className" will become "Systemd" for the systemd package.&lt;br /&gt;
&lt;br /&gt;
As for the "%()s" surrounding className, it's (the first argument to) Python's "string interpolation operator". Read the official documentation (&lt;a href="http://docs.python.org/library/stdtypes.html#string-formatting-operations%29"&gt;http://docs.python.org/library/stdtypes.html#string-formatting-operations&lt;/a&gt;) for details.&lt;br /&gt;
&lt;br /&gt;
But there is something strange. The % operator is defined as "format % values" and requires two operands. We have got the format "%()s", but where is the values?&lt;br /&gt;
&lt;br /&gt;
Values will be provided by conary automatically. That's how "macros" work in recipes. As in C, macros will come in handy sometimes. See &lt;a href="http://docs.rpath.com/conary/Conaryopedia/sect-macros.html"&gt;http://docs.rpath.com/conary/Conaryopedia/sect-macros.html&lt;/a&gt; for details.&lt;br /&gt;
&lt;br /&gt;
3. Line 2 to 25.&lt;br /&gt;
&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;font face="monospace"&gt;&lt;font color="#c000c0"&gt;name&lt;/font&gt; = '&lt;font color="#c00000"&gt;systemd&lt;/font&gt;'
&lt;font color="#c000c0"&gt;version&lt;/font&gt; = '&lt;font color="#c00000"&gt;15&lt;/font&gt;'
&lt;font color="#c000c0"&gt;buildRequires&lt;/font&gt; = ['&lt;font color="#c00000"&gt;autoconf:runtime&lt;/font&gt;', '&lt;font color="#c00000"&gt;automake:runtime&lt;/font&gt;', '&lt;font color="#c00000"&gt;audit:devel&lt;/font&gt;', ...]&lt;/font&gt;&lt;/pre&gt;These are the variables that will appear in most recipes and they are built into conary (for example conary has commands to query a package's name, version and buildRequires). Their meanings are obvious: package name, package version, and what you need to build this package. It's almost the same as in RPM .spec files.&lt;br /&gt;
&lt;br /&gt;
4. Line 29 to 47.&lt;br /&gt;
&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;font face="monospace"&gt;extraConfig = ()
patches = []
extraSources = []&lt;/font&gt;&lt;/pre&gt;These are the variables that I define for my own convenience. Later part of the recipe will make use of them.&lt;br /&gt;
&lt;br /&gt;
For now I only want to point out one thing. extraConfig seems to be a tuple, but it's actually a string. Not sure what's Python's official description but I use it as a trick to make the code look better.&lt;br /&gt;
&lt;br /&gt;
5. methods&lt;br /&gt;
&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;font face="monospace"&gt;&lt;font color="#af5f00"&gt;def&lt;/font&gt; &lt;font color="#008080"&gt;unpack&lt;/font&gt;(r):
&lt;font color="#af5f00"&gt;def&lt;/font&gt; &lt;font color="#008080"&gt;configure&lt;/font&gt;(r):
&lt;font color="#af5f00"&gt;def&lt;/font&gt; &lt;font color="#008080"&gt;policy&lt;/font&gt;(r):&lt;/font&gt;&lt;/pre&gt;Now we get to some Python functions. Each of them controls a part of the packaging process (extract the tarball, call "./configure", call "make", call "make install", etc).&lt;br /&gt;
&lt;br /&gt;
But where is the function that controls the whole process? It would be the job of setup() and it's being defined in the super-class AutoPackageRecipe. The class Systemd got it through inheritance.&lt;br /&gt;
&lt;br /&gt;
The class AutoPackageRecipe (defined in the package "autopackage") has such methods:&lt;br /&gt;
&lt;pre bgcolor="#ffffff" text="#000000"&gt;&lt;font face="monospace"&gt;&lt;font color="#af5f00"&gt; 7 &lt;/font&gt;    &lt;font color="#af5f00"&gt;def&lt;/font&gt; &lt;font color="#008080"&gt;setup&lt;/font&gt;(r):
&lt;font color="#af5f00"&gt; 8 &lt;/font&gt;        r.unpack()
&lt;font color="#af5f00"&gt; 9 &lt;/font&gt;        r.configure()
&lt;font color="#af5f00"&gt;10 &lt;/font&gt;        r.make()
&lt;font color="#af5f00"&gt;11 &lt;/font&gt;        r.makeinstall()
&lt;font color="#af5f00"&gt;12 &lt;/font&gt;        r.policy()
&lt;font color="#af5f00"&gt;13 &lt;/font&gt;
&lt;font color="#af5f00"&gt;14 &lt;/font&gt;    &lt;font color="#af5f00"&gt;def&lt;/font&gt; &lt;font color="#008080"&gt;unpack&lt;/font&gt;(r):
&lt;font color="#af5f00"&gt;15 &lt;/font&gt;        &lt;font color="#af5f00"&gt;pass&lt;/font&gt;
&lt;font color="#af5f00"&gt;16 &lt;/font&gt;    &lt;font color="#af5f00"&gt;def&lt;/font&gt; &lt;font color="#008080"&gt;configure&lt;/font&gt;(r):
&lt;font color="#af5f00"&gt;17 &lt;/font&gt;        r.&lt;font color="#008080"&gt;Configure&lt;/font&gt;()
&lt;font color="#af5f00"&gt;18 &lt;/font&gt;    &lt;font color="#af5f00"&gt;def&lt;/font&gt; &lt;font color="#008080"&gt;make&lt;/font&gt;(r):
&lt;font color="#af5f00"&gt;19 &lt;/font&gt;        r.&lt;font color="#008080"&gt;Make&lt;/font&gt;()
&lt;font color="#af5f00"&gt;20 &lt;/font&gt;    &lt;font color="#af5f00"&gt;def&lt;/font&gt; &lt;font color="#008080"&gt;makeinstall&lt;/font&gt;(r):
&lt;font color="#af5f00"&gt;21 &lt;/font&gt;        r.&lt;font color="#008080"&gt;MakeInstall&lt;/font&gt;()
&lt;font color="#af5f00"&gt;22 &lt;/font&gt;    &lt;font color="#af5f00"&gt;def&lt;/font&gt; &lt;font color="#008080"&gt;policy&lt;/font&gt;(r):
&lt;font color="#af5f00"&gt;23 &lt;/font&gt;        &lt;font color="#af5f00"&gt;pass&lt;/font&gt;&lt;/font&gt;&lt;/pre&gt;setup() is the only function that's required by conary to be defined in a recipe and determines how the packaging is done. But thanks for the recipe being Python code, you don't actually have to do it. It's sufficient to just override a few portions of setup(), where special processing is truly required. The other subroutines, namely make() and makeinstall(), can be used as is.&lt;br /&gt;
&lt;br /&gt;
6. "r"&lt;br /&gt;
&lt;br /&gt;
You might have noticed, the first parameter of all methods is an "r". And when methods are invoked, they have "r." before them. Suffice it to say, "r" in conary recipes is what "self" is in usual Python code. Refer to Python documentation for details.&lt;br /&gt;
&lt;br /&gt;
7. &lt;code&gt;unpack(r)&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
This is the first of our three methods. Here the source code of systemd is prepared for later compiling. A tarball, some patches and one extra configuration file are added to the project using built-in functions,addArchive(), addPatch() and addSource().&lt;br /&gt;
&lt;br /&gt;
The tarball will be extracted to the building directory (e.g. ~/conary/builds/systemd/). The patches will be applied on the source code. Then the extra sources will be copied into the building directory.&lt;br /&gt;
&lt;br /&gt;
The "patches" and "extraSources" defined above are used here, in a for-loop. It's only a engineering habit of me to list patches in the beginning of recipes. You could of course put them one by one in the for-loop, though I prefer otherwise.&lt;br /&gt;
&lt;br /&gt;
Again, "patches" is referenced as 'r.patches' and "r" is just like "self" here.&lt;br /&gt;
&lt;br /&gt;
8. &lt;code&gt;configure()&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
AutoPackageRecipe provides a straitforward configure() method which is just a thin wrapper of  r.Configure() (which is simply "./configure" under the hood, with some default options such as "--prefix=/usr").&lt;br /&gt;
&lt;br /&gt;
But systemd needs more. So I override it with my own configure(), which invokes "autoreconf" and passes some additional options. autoreconf is needed since I have patches against configure.ac and must get configure regenerated.&lt;br /&gt;
&lt;br /&gt;
9. &lt;code&gt;policy()&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Now we come to the last part of systemd.recipe. In my recipes policy() is usually used to finalize and clean up the packaging process.&lt;br /&gt;
&lt;br /&gt;
For every package, conary will run a bunch of "policies" against it, checking buildRequires, correcting obvious errors, normalizing against established customs, etc. For example, conary checks for non-executable files in directories that are "usually" for binary files (e.g. /usr/bin). But if you explicitly want such files, now is a good time to set "exceptions" to the policies.&lt;br /&gt;
&lt;br /&gt;
Most of the actions in systemd.recipe's policy() are conary policies, such as FixupMultilibPaths (&lt;code&gt;Fix up and warn about files installed in directories that do not allow side-by-side installation of multilib-capable libraries&lt;/code&gt;) and DanglingSymlinks (&lt;code&gt;Disallow dangling symbolic links&lt;/code&gt;).&lt;br /&gt;
&lt;br /&gt;
But Install() and Symlink() are not; they are build time functions just like Make() (&lt;code&gt;Runs make with system defaults&lt;/code&gt;) and MakeInstall (&lt;code&gt;Runs make utility with install target&lt;/code&gt;). In vim, build funtions and policy funtions will have different colors, thanks to the syntax file conaryrecipe.vim.&lt;br /&gt;
&lt;br /&gt;
For details of these conary API, reference to the manuals using "cvc explain &amp;lt;funtion name&amp;gt;".&lt;br /&gt;
&lt;br /&gt;
------------------&lt;br /&gt;
&lt;br /&gt;
That's the overview of systemd.recipe. I hope you get a taste of conary recipes (at least in my style :) Though it's not without its own shortcomings, conary recipes are the most elegant packaging scripts, compared to rpm, deb, bitbake and all the others that I've ever seen (most of them seem to be shell-based).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-1308362023664441823?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/pQ3CnAd6OBU" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/1308362023664441823?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/1308362023664441823?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2010/12/explanation-of-systemdrecipe.html" title="explanation of a systemd.recipe" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;DEcASX09eyp7ImA9Wx9QEE8.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-3914230504052238825</id><published>2010-12-22T21:54:00.000+08:00</published><updated>2010-12-22T21:54:08.363+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-22T21:54:08.363+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="life" /><title>2010 yearly summary</title><content type="html">It's already the last month of this year. Time to summarize and look forward into the future.&lt;br /&gt;
&lt;br /&gt;
2010 is surely an important period of time during my life. This year I graduated from university and got a job and finally have a life of my own. Looking back, there is actually more that has happened than I realized.&lt;br /&gt;
&lt;br /&gt;
So what happened during my 2010:&lt;br /&gt;
&lt;br /&gt;
1. I graduated from Beihang University. It's 2006 that I came to Beijing and now four years have passed, it's surely a great tour.&lt;br /&gt;
&lt;br /&gt;
2. Beginning in the later part of 2009, I have an 8-months internship at Sun Microsystems. Even though it's also the last few months of the Sun company, I've a great time there and I always missed the colleagues from the first company that I worked for. Thank you, Lingbo, Aaron, Edward, Edgar, Miao, Emily. And there are many more whom I can't all list here, but I always feel grateful for them when I think of the help that they gave me.&lt;br /&gt;
&lt;br /&gt;
3. Then I got a job at Wind River. It began in May, so it's already seven months! In this position I have been learning more and more about Linux, and although I don't much coding, there are plenty of chances to get knowledge about what I want.&lt;br /&gt;
&lt;br /&gt;
4. I managed to keep up with our Open Source Club. In the first half of the year, it became quite silent since people are busy graduating. But we got over it and things are much better now.&lt;br /&gt;
&lt;br /&gt;
5. About my participation in open source projects, Foresight Linux is the only one in which I'm still active. I gradually dropped out of the others and stopped appearing in local open source meetings. That's kind of sad, which I hope will be changed in the future. On the other hand, I'm happy that we are keep sticking together around Foresight Linux, even it's still so small. 2009 was such a hard year for many people, but we are seeing better in 2010 and hopefully even better in 2011.&lt;br /&gt;
&lt;br /&gt;
6. Until now I wrote 17 blogs during 2010 (20 in 2009 and 31 in 2008). You can't judge everything simply through numbers, but it still means something. I may still post one or two more articles, so the final number will be 20 and on average, it's 18 days per post.&lt;br /&gt;
&lt;br /&gt;
7. The books I read in this year include Lord of the Rings, 1984, Lincoln the Unknown, More Joel on Software (in Chinese), 程序员羊皮卷 (a book on programmer career), Linux Application Development (not quite finished), Linux Programming by Example (in Chinese; not quite finished), Brain Rules (in progress), 程序员的自我修养 (similar topic as in Linkers and Loaders; in progress) and Apprenticeship Patterns (in progress). There might be some that I didn't write down but yeah, I should read more.&lt;br /&gt;
&lt;br /&gt;
8. I have been memorizing English words for about two months, and it feels very good.&lt;br /&gt;
&lt;br /&gt;
That's it. Year 2010.&lt;br /&gt;
&lt;br /&gt;
What do I have in mine about the new year?&lt;br /&gt;
&lt;br /&gt;
1. Write more blogs. I don't have goals but 20 to 30 should be good.&lt;br /&gt;
&lt;br /&gt;
2. Read more books. Again I don't have goals, but I will read more on various topics. And since no one is giving me homework now, I will have more liberty as for what to read.&lt;br /&gt;
&lt;br /&gt;
3. Participation in open source projects and meetings. I'll go to meetings and try to get into some projects. For now I have Foresight Linux and systemd in mind.&lt;br /&gt;
&lt;br /&gt;
4. Keep active in Beihang Open Source Club. It feels great to be among students. Though I was a student not long ago, I'm not now. I'll help get our club going forward with my friends in the university.&lt;br /&gt;
&lt;br /&gt;
Let's see how it goes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-3914230504052238825?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/WazJixp0ABw" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/3914230504052238825?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/3914230504052238825?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2010/12/2010-yearly-summary.html" title="2010 yearly summary" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;DkENRno5cSp7ImA9Wx9RGE8.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-2156680347754391376</id><published>2010-12-18T21:39:00.000+08:00</published><updated>2010-12-20T13:58:17.429+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-20T13:58:17.429+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="qemu" /><title>get serial port output from qemu</title><content type="html">So I was testing systemd in qemu, and wanted to see its debug output. Here is how I managed to do it.&lt;br /&gt;
&lt;br /&gt;
1. Start qemu with the serial port redirected somewhere. I chose to redirect to a file since that would be searchable.&lt;br /&gt;
&lt;br /&gt;
qemu-kvm &lt;other-options&gt; FL-devel-dev.img &lt;b&gt;-serial file:/tmp/systemd-console&lt;/b&gt;&lt;/other-options&gt;&lt;b&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
-serial will redirect the serial port output to the file.&lt;br /&gt;
&lt;br /&gt;
(The other options I use are "-vga vmware -m 512M -redir tcp:5555::22", but it's irrelevant here.)&lt;br /&gt;
&lt;br /&gt;
2. Tell the kernel that the console is on the serial port.&lt;br /&gt;
&lt;br /&gt;
Edit the bootloader config and add &lt;b&gt;console=ttyS0&lt;/b&gt; to the kernel arguments.&lt;br /&gt;
&lt;br /&gt;
You may also need to remove "splashy", "quiet" or others.&lt;br /&gt;
&lt;br /&gt;
Now you can inspect the log file on the host.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-2156680347754391376?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/M0RLq6GuaUo" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2156680347754391376?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/2156680347754391376?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2010/12/get-serial-port-output-from-qemu.html" title="get serial port output from qemu" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry><entry gd:etag="W/&quot;DkAHQX4-fSp7ImA9Wx9RGE8.&quot;"><id>tag:blogger.com,1999:blog-7699237061780229842.post-8416507725816669695</id><published>2010-11-03T17:24:00.005+08:00</published><updated>2010-12-20T13:58:50.055+08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-20T13:58:50.055+08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="systemd" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="c" /><title>per-process mount namespace</title><content type="html">systemd 用到了这么一段代码，用来读取系统上的挂载信息：&lt;br /&gt;
&lt;pre style='color:#000000;background:#ffffff;'&gt;m&lt;span style='color:#808030; '&gt;-&lt;/span&gt;&lt;span style='color:#808030; '&gt;&gt;&lt;/span&gt;proc_self_mountinfo &lt;span style='color:#808030; '&gt;=&lt;/span&gt; fopen&lt;span style='color:#808030; '&gt;(&lt;/span&gt;&lt;span style='color:#800000; '&gt;"&lt;/span&gt;&lt;span style='color:#0000e6; '&gt;/proc/self/mountinfo&lt;/span&gt;&lt;span style='color:#800000; '&gt;"&lt;/span&gt;&lt;span style='color:#808030; '&gt;,&lt;/span&gt; &lt;span style='color:#800000; '&gt;"&lt;/span&gt;&lt;span style='color:#0000e6; '&gt;re&lt;/span&gt;&lt;span style='color:#800000; '&gt;"&lt;/span&gt;&lt;span style='color:#808030; '&gt;)&lt;/span&gt;
&lt;/pre&gt;奇怪之处在于 mountinfo 这个文件是在 self 目录下，而不是 /proc 的最上层。也就是说，它是进程相关的，而不是整个系统范围的。&lt;br /&gt;
&lt;br /&gt;
所以... 原来有 per-process mount namespace 这么个东西。&lt;br /&gt;
&lt;pre&gt;$ man proc
    /proc/[pid]/mountinfo (since Linux 2.6.26)
        This file contains information about mount points.

   /proc/mounts
        Before kernel 2.4.19, this file was a list of all the file systems currently
        mounted on the system.  With the introduction  of  per-process  mount
        namespaces  in  Linux  2.4.19,  this  file  became  a link to
        /proc/self/mounts, which lists the mount points of the process's own mount
        namespace.

$ man 2 mount
    Per-process Namespaces
        Starting with kernel 2.4.19, Linux provides per-process mount namespaces.  A
        mount namespace is the set of file system mounts that are visible to a process.
        Mount-point namespaces can be (and usually are) shared between multiple
        processes, and changes to the namespace (i.e., mounts and unmounts) by one
        process are visible to all other processes sharing the same namespace.  (The
        pre-2.4.19 Linux situation can  be considered as one in which a single
        namespace was shared by every process on the system.)

        A child process created by fork(2) shares its parent's mount namespace; the
        mount namespace is preserved across an execve(2).

        A  process  can  obtain a private mount namespace if: it was created using the
        clone() CLONE_NEWNS flag, in which case its new namespace is initialized to be
        a copy of the namespace of the process that called clone(); or it calls
        unshare(2)  with  the  CLONE_NEWNS  flag,  which causes  the caller's mount
        namespace to obtain a private copy of the namespace that it was previously
        sharing with other processes, so that future mounts and unmounts by the caller
        are invisible to other processes (except child processes that the caller
        subsequently creates) and vice versa.
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7699237061780229842-8416507725816669695?l=blog.zhangsen.org' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/zhangsen-blog/~4/bA8JbxMBYWc" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/8416507725816669695?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7699237061780229842/posts/default/8416507725816669695?v=2" /><link rel="alternate" type="text/html" href="http://blog.zhangsen.org/2010/11/per-process-mount-namespace.html" title="per-process mount namespace" /><author><name>Jesse</name><uri>http://www.blogger.com/profile/13216179253923165798</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author></entry></feed>

