这篇是纯水,实际这应该算是我的头一个正经一点的 patch ,合进去当时还挺高兴的,也感觉算是个“里程碑”,尽管这个 patch 并没有啥技术含量。

起因

前一段时间手头的任务是把深度文管的网络设备管理部分重构掉,由于之前文管做这部分的代码耦合度炒鸡高,而一旦把我重构的部分替换掉现有的部分就会动非常多的代码以至于可能造成成堆的我测不到的 BUG ,正逢即将冻结代码,所以我那部分就只先找了个耦合度不是非常高的地方换了上去,剩下的时间就用来修 bug 以及看看有没有别的可以改善的地方。

任务列表里有一个一直放着的任务是有一部分 office 文档不能正确显示成“文档”类型,于是第一反应是拿到显示不对的文档然后看 MIME 类型是什么。深度文管的文件类型一列写的几个类型是固定的,每一种类型对应一个 MIME 类型列表,而如果这个列表中找不到这个类型,就会显示成未知类型了。

要到样本文档然后把对应的 MIME 类型加到列表里之后,我还是觉得哪里不对。查了一下 Office 文档的 MIME 类型列表 后发现明显还有一堆类型是没加进深度文管的列表里去的,但我觉得这样挨个加并不是个办法,于是打开 nautilus 看看它是怎么显示的,于是看到了 nautilus 显示了正确的文件类型文字描述,然后开始蛋疼:它是怎么显示这个东西的,难不成也是个表?

由于不熟悉于是只能去看文档,后来在文档里发现 QMimeType 是有一个 comment() 属性的,把这个值拿出来发现就是 nautilus 所显示的描述文字,于是我就给在 QT_DEBUG 情况下编译的文管加了个功能 1 ,显示实际的 MIME comment 而不是查表的结果,照理说这事儿就结束了。

然后我反应过来一回事,WPS 的文档用了他们自己的 MIME 类型而不是上面所查到的列表的那些类型,那我得先试试 WPS 的这些文档类型能不能正确显示,于是就装了 WPS 并测试,结果发现并不能,显示的结果是 MIME 类型的字符串结果,打开 dolphin 之后发现 dolphin 显示的结果和我一样,于是放心并打开 nautilus 打算验证一下,却发现 nautilus 能够显示正确的描述文字…

这下可好,看 qt 的源码吧。

定位 bug

首先根据文档找到了 /usr/share/mime/packages/ 并查看 WPS 所给的 shared MIME database 文件,发现它并没有给出 xml:langzh_CN 的 comment 值,而是给了一个只包含描述的空属性的 comment 元素。打开 qtbase 的代码后很容易的找到 qmimetype.cpp ,找到 QMimeType::comment(),然后发现 comment 内容来自 d->localeComments 以及这里只尝试了 QLocal().name()QLocal().uiLanguage() 所对应的语言,顺着找到了 qmimeprovider.cpp,发现会把读取的空属性 comment 元素作为 en_US 的 locale 处理。于是问题找到:我们所用的 locale 是 zh_CN ,而其并没有对应的 comment 内容,而这里也没有 fallback 措施,故自然找不到了。

交 patch

定位到 bug 自然也就好解决了,于是最初的改法则是简单的加个 en_US locale 的 fallback,一行代码。然后本地编译测试,然后 LD_PRELOAD 编译好的东西去测试是不是改好了,确认之后就打算交 patch 了。

给正经项目交 patch 首先肯定得看看流程,于是第一件事先去开了个 BUG ,描述了原因后给贴上了最小复现代码,然后再去交 patch 。由于 Qt 用的也是 gerrit ,所以交 patch 自然稍微熟悉了一些,不过由于使用的 gerrit 主题不同我还是遇到了一些小问题,尽管所幸都没构成阻碍。Patch 自然还是只有那一行,由于没玩过 Qt 的单元测试于是也没有带上单元测试,问过之前交过 patch 的同事说是他之前也没交单元测试,于是我就放心交上去了。

git review -r origin 5.11 之后 Qt Sanity Bot 上来就来个 -1 ,然后发现 Commit Message 连多余的空行都不让有,改完终于过了 Qt Sanity Bot 的检查。不过人还是比 Bot 严格一些的,由于我的辣鸡英文水平,还是被叫改了 Commit Message 中的一些问题,最终得到了 +1 。当天是 10 月 23 日,我还想着说不定 1024 当天就能 merge 进去 2,结果还是因为少单元测试吃了个 -1。

其实大概 review 的那位可能没搞懂问题在哪,于是觉得我加了个没必要的 fallback ,而后来我把逻辑稍微改了一点后他发现的确是有用的,于是就认同修改了。不过他之前就有评论让我写单元测试(就是那个 -1)不过因为 gerrit 主题不太习惯所以我漏看了,于是看到之后我只能硬着头皮看怎么写单元测试。所幸这个单元测试并不难写,我甚至不需要单独提供出错的 MIME database 文件。改完之后那位 +1 并告诉我 5.11 已经不收代码了,于是我的 patch 移动到了 5.12 分支上来。移动之后终于得到了 +2,于是我点了 stage change 却发现冲突了。于是只好本地 rebase 完再提交 3。再次拿到 +2 后点 stage change 等待 CI 跑测试,想着就能合并进去了,结果发现 CI 跑挂了,而正错在我的单元测试上。

讲实话我写完单元测试后只是试过了编译能过,但没试过能不能跑单元测试。由于当时编译 qtbase 用的并不是 development-build ,直接跑单元测试告诉我确少某个 feature,于是直接停了。现在发现单元测试出了问题,只能想着看看怎么跑起来单元测试。后来注意到有 development-build 后试了试它4,果然就能跑单元测试了,于是发现还有一处位置需要修改,改完跑单元测试通过,实际测试也没问题,就交了新的 patch。并再次拿到 +2 5

等 CI 构建

于是就是等 CI 编译了。漫长等待后发现 CI 又挂了,于是看报错却发现好像和我没什么关系,又看了看同时提交编译的几个提交,也都有了相同的错误,于是我直接点了 stage change 并等待下一次构建结果,得到的却还是失败。由于输出的确和我没什么关系,于是我只能再次触发,这样反复六次之后发现还是挂,于是我开始怀疑是不是我哪里搞错了。直接在 gerrit 回复里问是不是出了问题,没有得到结果,又重试了几次还是挂掉,于是发邮件过去问,得到说是 CI 这几天抽风,让我再等几天重试就好,于是我只能接着重试。由于看着实在没有好起来的迹象,我看了看万年都没敢动一次的 IRC ,注册了 freenode 然后跑去 #qt-labs 里问,得到的还是相同的答复。

没办法,我就只能接着重试咯,就早上点一下晚上点一下,看看能不能集齐所有的报错,昨天(11/2)白天实在觉得无奈了,感觉得个十天半个月大概才能好过来,于是立了个 flag ,说三天内这 patch 能合进去我就直播吃猫粮…然后当天晚上就发现 CI 跑通过合并进去了,而这是我第 18 次重试……

最后

这次 patch 就这么合并了进去,算下来我之前给别的项目做过的贡献,(除了深度之外)基本都是 issue 和中文本地化之类的内容了。头一次代码贡献多少还是值得纪念一下的,至于这个过程学到了点啥…

  • 单元测试是很有用的
  • 不要随便立 flag
  • 如果想让事情能有转折,那就立 flag

最后,惯例,2018年11月3日20点06分。

  1. 深度的软件开发还是很商业驱动的,产品和设计基本完全决定了程序应该怎样工作,一些东西即便标准里有,然而和产品或设计所给出的要求不一样,那就不能加进去… 

  2. 不知道啥时候开始,十月二十四就突然成了国内的程序员节。虽然我并不过这个不过如果这天合进去的话还是多少有那么点“意思”的所以… 

  3. 不清楚 git review 实际做了什么,我试着 git review -D change_id 直接报错了(深度的 cr 上用就好好的,更新 git-review 也不管用),最终解决冲突还是研究了一会儿一些平时没用过的 git 技巧才推上去新的 patch。 

  4. 最后构建用的是 ../qtbase/configure -developer-build -confirm-license -opensource -no-gui -no-dbus -no-accessibility -no-opengl -no-widgets -no-compile-examples -make tests。其中禁用了一部分东西以加快编译速度。另外 -make tests 我不清楚是不是多余的,感觉如果不写的话就不会编译所有的测试代码,或许会快上一些,但是没试过,不确定到底是不是这样。 

  5. review 的那位评论说 “See, unittests are very useful :-)”,我现在是真的完全赞同了。