如何在 Shake 中显示进度?

How to show progress in Shake?

我想弄清楚如何在执行命令之前从进度类型(在 Development.Shake.Progress 中)获取进度信息以输出它。可能需要的输出是:

[1/9] Compiling src/Window/Window.cpp
[2/9] Compiling src/Window/GlfwError.cpp
[3/9] Compiling src/Window/GlfwContext.cpp
[4/9] Compiling src/Util/MemTrack.cpp
...

现在我正在使用一些 IORef 来模拟这个,它保持总数(最初设置为源文件的总和)和我在执行每个构建命令之前增加的计数,但这对我来说似乎是一个 hackish 解决方案.

最重要的是,此解决方案似乎可以在干净的构建上正常工作,但在部分构建上表现不佳,因为显示的总和仍然是所有源文件的总和。

通过访问 Progress 数据类型,我将能够使用其 countSkipped、countBuild 和 countTodo 成员正确计算此分数(请参阅 Progress.hs:53),但我仍然不确定如何才能我做到了。

感谢任何帮助。

Progress 类型的值目前只能用作存储在 shakeProgress 中的函数的参数。您可以随时通过以下方式获得 Progress

{-# LANGUAGE RecordWildCards #-}
import Development.Shake
import Data.IORef
import Data.Monoid
import Control.Monad

main = do
    ref <- newIORef $ return mempty
    shakeArgs shakeOptions{shakeProgress = writeIORef ref} $ do
         want ["test" ++ show i | i <- [1..5]]
         "test*" %> \out -> do
             Progress{..} <- liftIO $ join $ readIORef ref
             putNormal $
                "[" ++ show (countBuilt + countSkipped + 1) ++
                "/" ++ show (countBuilt + countSkipped + countTodo) ++
                "] " ++ out
             writeFile' out ""

这里我们创建了一个 IORef 来存储传递给 shakeProgress 的参数,然后在 运行 规则时检索它。 运行上面的代码我看到了:

[1/5] test5
[2/5] test4
[3/5] test3
[4/5] test2
[5/5] test1

运行 在更高的并行度下给出不太精确的结果 - 最初只有 3 个待办事项(摇动增量 countTodo 因为它找到待办事项,并在它找到待办事项时立即生成项目知道其中任何一个),并且在同一索引处通常有两个规则 运行(没有关于有多少正在进行的信息)。鉴于您的特定规则的知识,您可以优化输出,例如存储一个 IORef 递增以确保索引是单调的。

此代码有些复杂的原因是 Progress 信息旨在用于异步进度消息,尽管您的方法似乎完全有效。可能值得为同步进度消息引入 getProgress :: Action Progress 功能。