避免使用Oracle,或分隔相同类型的Oracle

问题描述

我有以下情况:

  • find-deps一个运行速度非常快的外部程序,它类似于ghc -M发现依赖项信息。其输出是一些文件deps
  • compile一个外部程序,运行速度非常慢;与ghc --make不同,即使输入没有任何更改,它也非常慢。

因此,想法是添加一个运行find-deps的Shake规则以生成deps,将其解析为文件srcs的列表,然后编译规则将{{1} },以确保仅在need srcs发现的任何源已更改的情况下重新运行compile

棘手的部分是find-deps需要find-deps才能发现新依赖的源文件。因此,现在如果alwaysRerun规则依赖于compile获取文件列表,那么它也将deps。标准解决方案是使用一个oracle:我们可以添加一个alwaysRerun的{​​{1}}的oracle,并将其解析为文件列表,然后need规则首先会要求源文件列表,仅deps。因此,compile的{​​{1}}链上没有need

但是,就我而言,我不是在编写特定的Shakefile。相反,我正在编写一个可重用的alwaysRerun库,用户可以使用该库来制作自己的主Shakefile。所以我需要将其打包成类似

的格式
need

但是我应该将compile的{​​{1}}部分放在哪里,并对其进行解析并返回源文件列表?我不能将其放在Rules中,因为然后使用不同目录的两次myRules :: FilePath -> Rules () myRules dir = do dir </> "deps" %> \depFile -> do alwaysRerun cmd_ (Cwd dir) "find-deps" ["-o",depFile] dir </> "exe" %> \exeFile -> do srcs <- askOracle $ Sources dir need srcs cmd_ (Cwd dir) "compile" ["-o",exeFile] 调用将尝试为同一类型两次安装一个oracle处理程序。而且我无法使addOracle $ \Sources dir -> ...成为oracle问题类型的一部分,因为它是术语级变量,所以我无法将其提升到查询need [dir </> "deps"]索引中。

这给我留下了一些超级含义,例如让用户记住要在其Shakefile中仅包含一次rules

所以我的问题是:

  • 有没有一种方法可以跟踪依赖关系(即在没有源文件更改的情况下避免运行rules不涉及oracle
  • 或者,是否可以通过某种方式对其进行范围划分来分隔相同类型的oracle ,这样我就可以将此dir oracle仅添加到{ {1}}?

解决方法

有没有一种方法可以在不涉及Oracle的情况下跟踪依赖关系?

是-如果find-deps的输出完全没有变化,则不会重建compile。您可以通过指定诸如Change之类的ChangeModtimeAndDigest值来实现,但这是一个全局设置。另外,您可以将find-deps的输出放在foo.deps.out之类的位置,然后调用copyFileChanged "foo.deps.out" "foo.deps",如果文件未更改,则不会更新时间戳。

有没有办法分隔相同类型的预言片?

虽然我能理解为什么有用,但并不容易且立即。我可以想到两种可能的解决方法:

  1. 可以添加addOracleIdempotent,而该Rules会忽略有关重复添加同一oracle的任何错误。对Shake来说,这是一个比较容易的更改(基本上在dir中设置了一个标志来忽略重复项)。
  2. 或者,您可以尝试将copyFileChanged提升为类型级别,并确保每个oracle具有不同的类型。这可能会使您的API更复杂,并且需要输入魔术。

在所有这些解决方案中,我将使用import logging logging.basicConfig(filename='tgbot.log',level=logging.INFO) def log(m: Message): username = m.from_user.username logging.info(username) ,因为它简单而本地。