问题描述
我有一个游戏的多项目设置.有一个非常具体的子项目叫做资源",它只包含要打包到 jar 中的图像、声音和 texfiles 等文件.
I have a multi-project setup for a game. There is a very specific sub project called 'resources' that only contains files like images, sounds and texfiles to be packed into a jar.
我有一个自定义任务来处理图像并打包它们.在src/main"中,我使用了一个文件夹预处理",图像应该放在那里,一个非托管"文件夹用来存放其他所有东西.通过运行我的任务,预处理"中的所有图像都被打包并输出到资源"中,非托管"中的所有内容都按原样复制.
I have a custom task that processes images and packs them. Inside 'src/main' I'm using a folder 'preprocess' where images should go and an 'unmanaged' folder where everything else goes. By running my task all images in 'preprocess' gets packed and output to 'resources' and everything in 'unmanaged' is copied as is.
val texturePacker = TaskKey[Unit]("texture-packer", "Runs libgdx's Texture Packer")
val texturePackerTask = texturePacker := {
println("Packaging textures...")
val inputDir = file("resources/src/main/preprocess")
val outputDir = file("resources/src/main/resources")
val folders = inputDir.asFile.listFiles filter (_.isDirectory)
println("Sub-Folders:" + folders.mkString(", "))
// Run Texture Packer
for (subfolder <- folders) {
println("Building assets for:" + subfolder)
val args = Array(subfolder.toString, outputDir.toString, subfolder.getName)
com.badlogic.gdx.tools.imagepacker.TexturePacker2.main(args)
}
// Copy unmanaged resources
IO.copyDirectory(file("resources/src/main/unmanaged"), file("resources/src/main/resources"))
}
然后在设置中的资源"项目:
And then inside the settings the 'resources' project:
...
packageBin in Compile <<= packageBin in Compile dependsOn(texturePacker)
...
其他子项目依赖于与其运行相关的 packageBin.这样,每当我运行项目时,我都会获得最新的资源状态.我不希望它随需应变.问题是每次运行都需要很长时间来处理.我知道 SBT 支持缓存 SBT FAQ 但我不明白如何使其适应我的任务.
The other sub projects have a dependency on packageBin associated with their run. That way whenever I run the project I get the most up to date state of resources. I don't want it to be on demand. The problem is that it takes a long time to process for every run. I know SBT supports caching SBT FAQ but I don't understand how to adapt it to my task.
如果文件夹列表中的子文件夹中的文件未被修改,如何使我的自定义任务避免重做工作?
How can I make my custom task avoid redoing the work if the files in a subfolder from the folders list were not modified?
推荐答案
解决方案
这里有一个可能适合您的解决方案.但是,我并不完全理解 FileFunction.cached
是如何工作的(代码后面有更多信息),所以这可能不是最好的解决方案:
Solution
Here is a solution that might suite you. However, I don't fully understand how FileFunction.cached
works (more information after the code), so this is probably not the best possible solution:
val testCache = TaskKey[Unit]("test-cache", "Test SBT's cache")
val testCacheTask = testCache := {
println("Testing cache ...")
val inputDir = file("test/src") /* Take direct subdirectories from here */
val outputDir = file("test/dest") /* Create archives here */
val cacheDir = file("test/cache") /* Store cache information here */
/* Get all direct subdirectories of inputDir */
val folders = inputDir.asFile.listFiles.filter{_.isDirectory}
folders.foreach{folder =>
/* Get all files in the folder (not recursively) */
val files = folder.listFiles.toSet
/* Wrap actual function in a function that provides basic caching
* functionalities.
*/
val cachedFun =
FileFunction.cached(cacheDir / folder.name,
FilesInfo.lastModified, /* inStyle */
FilesInfo.exists) /* outStyle */
{(inFiles: Set[File]) =>
createJarFromFolder(folder,
inFiles,
outputDir / (folder.name + ".jar"))
}
/* Call wrapped function with files in the current folder */
cachedFun(files)
}
}
/* Creates a JAR archive with all files (this time recursively) in
* the given folder.
*/
val createJarFromFolder = (folder: File, inFiles: Set[File], outJar: File) => {
println("At least one of the %d files in %s have changed. Creating %s."
.format(inFiles.size, folder, outJar))
/* Replace this by your actual operation */
val cmdSeq = Seq("jar", "cf", outJar.toString, "-C" , folder + "/", ".")
println("cmdSeq = " + cmdSeq)
println("jar: " + cmdSeq.!!)
Set(outJar)
}
注意事项
我对
cached
的理解是,它检查inFiles
是否有修改,如果one,它会调用实际操作集中的文件已更改.changed 的确切含义由cached
的inStyle
参数决定.Notes
My understanding of
cached
is, that it checks theinFiles
for modifications, and that it invokes the actual operation if one of the files in the set changed. The exact meaning of changed is determined by theinStyle
argument tocached
.直接将目录传递给
cached
会很好,这样如果该目录中的任何内容发生变化,就会执行实际操作.但是,我怀疑目前是否可行.It would be nice to directly pass a directory to
cached
, such that the actual operation is performed if anything in that directory changes. However, I doubt that it is currently possible.我不太明白实际操作返回的文件集的行为是什么(此处:
Set(outJar)
).我假设cached
的outStyle
参数与此相关,并且我希望在 JAR 不存在时调用createJarFromFolder
(无论更改输入文件),但情况似乎并非如此.也就是说,如果您删除了一个 JAR 文件,但没有更改相应目录中的其中一个文件,则不会重新创建该 JAR.I don't quite get what the behaviour with respect to the set of files returned by the actual operation is (here:
Set(outJar)
). I assume that theoutStyle
argument tocached
is related to this, and I expectedcreateJarFromFolder
to be called whenever the JAR does not exist (regardless of changes to the input files), but that doesn't seem to be the case. That is, if you delete a JAR file but not change one of the files in the corresponding directory, the JAR will not be recreated.该代码有点狡猾,因为在决定该文件夹中是否发生更改时,它只考虑位于特定文件夹顶部的文件.您可能希望进行递归.
The code is somewhat dodgy, because it only considers the files that are at the top of a particular folder when it comes to deciding if changes occurred in that folder. You probably want to make that recursive.
我很想看到一种更好的方式来使用 SBT 的缓存功能.如果您从邮件列表中获得更多信息,请在此处发布.
I'd love to see a better way of using SBT's caching feature. Should you get more information, e.g., from the mailing list, please post them here.
这篇关于如果输入文件不变,如何使自定义任务避免重做工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!