我经营着托管持续集成公司,我们在 Linux 上运行客户的代码。每次运行代码时,我们都在单独的虚拟机中运行。经常出现的问题是,客户的测试有时会因为在 VM 上签出的代码的目录顺序而失败。
让我更详细地讲一下。在 OSX 上,HFS+ 文件系统确保目录始终以相同的顺序遍历。使用 OSX 的程序员认为,如果它在他们的机器上工作正常,那么它就必须在任何地方工作正常。但它在 Linux 上通常不起作用,因为 Linux 文件系统在遍历目录时不提供顺序保证。
举个例子,假设有两个文件,a.rb,b.rb。a.rb 定义MyObject
,b.rb 使用MyObject
。如果先加载 a.rb,则一切正常。如果先加载 b.rb,它将尝试访问未定义的变量MyObject
,并失败。
但更糟糕的是,它并不总是会失败。由于 Linux 上的文件系统排序不是有序的,因此在不同的机器上顺序会有所不同。这更糟糕,因为有时测试会通过,有时测试会失败。这是最糟糕的结果。
所以我的问题是,有没有办法让文件系统的排序可重复。也许是 ext4 的一些标志,表示它将始终按某种顺序遍历目录?或者也许是具有此保证的其他文件系统?
答案1
我知道这不是你想要的答案,但我相信正确的解决方案是避免取决于目录中文件的顺序。也许它在所有 HFS+ 文件系统中始终保持一致,也许您可以找到一种方法使其在 ext4 或其他文件系统中也保持一致,但从长远来看,这会给您带来比节省的更多麻烦。使用您的应用程序的其他人会遇到令人不快的意外,因为他们没有意识到它仅与某些类型的文件系统兼容,而与其他类型的文件系统不兼容。如果从备份中恢复文件系统,顺序可能会发生变化。您可能会遇到兼容性问题,因为 HFS+ 一致顺序和 ext4 一致顺序可能不一样。
只需读取所有目录条目,然后按字典顺序对列表进行排序,然后再使用即可。就像这样ls
做一样。
您提到了文件a.rb
和b.rb
,但如果我们谈论的是编程语言源文件,那么每个文件是否都应该负责确保导入所有依赖项?
答案2
Linux readdir() 中的 POSIX 调用不保证任何一致的顺序。如果您想要有序的结果,处理文件的应用程序负责对如何将它们呈现给调用函数进行排序。
https://stackoverflow.com/questions/8977441/does-readdir-guarantee-an-order
现在,既然你说这是你客户的代码,你无法修复它,那么你可能会修改用于提供一致 readdir() 调用的链接库。这需要一些工作,值得单独提出问题。有关此内容的快速参考,请参阅http://www.ibm.com/developerworks/linux/library/l-glibc/index.html。
更改此设置可能会引发一系列我无法预见的其他问题。强烈建议您这样做,但如果您的客户无法得到适当的教育,这可能是一个解决方案。
答案3
现代 Linux (ext4) 为文件列表添加了 B 树索引。其效果之一是默认文件顺序取决于其名称的哈希值。
要禁用此功能,请使用:
tune2fs -O^dir_index
答案4
告知您的客户,存在一个应明确说明的固有顺序依赖关系。主动帮助客户以编译在所有系统上都能正常工作的方式表达依赖关系,并让客户采用捕获编译顺序依赖关系的更改流程。
如果客户希望能够在其他机器上进行编译,那么他们认为它是免费的,那就太无礼了。