我使用uptodate? Ruby中的方法,以确定文件是否必须重新编译/重新链接/重新生成等。有时我使用的构建框架在这些步骤中如此之快,以至于输出文件和先决条件文件具有完全相同的文件修改时间戳。这会导致构建框架不必要地重新编译/重新链接文件。
我比较像这样的建筑时间戳 -
compile_file(file) unless uptodate?(file, %W(#{dependencies}))
我查找了uptodate的来源?来自here,它看起来像这样 -
def uptodate?(new, old_list, options = nil)
raise ArgumentError, 'uptodate? does not accept any option' if options
return false unless File.exist?(new)
new_time = File.mtime(new)
old_list.each do |old|
if File.exist?(old)
return false unless new_time > File.mtime(old)
end
end
true
end
如所怀疑的,如果时间戳相等,则返回false。解决这个问题最优雅的方法是什么?我试过在Linux和Windows上运行该框架,我遇到了同样的问题。根据我的阅读here,它不太可能是文件系统特定的文件修改时间分辨率问题(因为ext4的分辨率为1微秒)。
答案 0 :(得分:2)
Ruby的File
对象似乎不支持文件修改时间戳的亚秒级解析,即使底层文件系统也是如此。一种解决方案是shell ls --full-time
并使用Ruby的DateTime
解析结果,它支持几秒的分数:
module FileUtilsPlus
def self.uptodate?(new, old_list, options = nil)
return true if FileUtils.uptodate?(new, old_list, options)
return false unless File.exist?(new)
new_time = filemtime(new)
old_list.each do |old|
if File.exist?(old)
return false unless new_time > filemtime(old)
end
end
end
def self.filemtime(path)
DateTime.parse(`ls --full-time foo | awk '{ print $6 " " $7 }'`)
end
end
请注意,这将比Ruby的本机文件操作慢得多,所以如果FileUtils::uptodate?
返回false,我们只会这样做。
答案 1 :(得分:1)
uptodate?
似乎是正确的。如果时间戳相等,则文件可能是最新的,也可能不是。因此,它在安全方面犯了错误,并宣布它已过时。
在构建文件的步骤中,添加逻辑以使构建文件的时间等于其依赖的时间。是的,这是一个黑客攻击,但在这种情况下你可能是最好的。
某些文件系统(ext4等)可以存储亚秒级分辨率的时间戳,可能值得一看。
除非上述任何一项,你可以修补猴子补丁吗?或者只是在时间戳相等的情况下创建自己的错误,而不是建立错误。