如何在Shake中显示进度?

时间:2015-08-21 12:30:41

标签: haskell shake-build-system

我试图找出如何从Progress类型(在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解决方案。 / p>

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

通过访问Progress数据类型,我可以使用countSkipped,countBuild和countTodo成员正确计算这个分数(参见Progress.hs:53),但我仍然不确定如何实现这一点。

感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

类型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

以更高的并行度运行会得到不太精确的结果 - 最初todo中只有3个项目(Shake会增加countTodo,因为它会找到项目todo,并在知道任何项目后立即生成项目) ,并且通常有两个规则在同一个索引上运行(没有关于有多少正在进行中的信息)。根据您的特定规则的知识,您可以优化输出,例如存储一个IORef增量以确保索引是单调的。

此代码有点令人费解的原因是Progress信息旨在用于异步进度消息,尽管您的方法似乎完全有效。可能值得为同步进度消息引入getProgress :: Action Progress函数。